有人可以给我提供一个例子
invmap :: (a -> b) -> (b -> a) -> f a -> f b
对于不变式有什么好处?
最佳答案
通常,人们不使用Invariant
。您想要的原因是,如果您正在使用一种变量同时出现在协变和反变位置的类型。
newtype Endo a = Endo {appEndo :: a -> a}
newtype Foo a = Foo (Maybe a -> IO a)
data Bar a = Bar [a] (a -> Bool)
这些都不是
Functor
或Contravariant
的实例,但是它们都可以是Invariant
的实例。人们很少打扰的原因是,如果您需要对此类类型进行大量映射,那么通常最好将其分解为协变和反变量部分。每个不变函子可以用
Profunctor
表示:newtype FooP x y = FooP (Maybe x -> IO y)
data BarP x y = Bar [y] (x -> Bool)
现在
Endo a ~= (->) a a
Foo a ~= FooP a a
Bar a ~= BarP a a
-- So we'd likely write newtype Bar a = Bar (BarP a a)
通常,如果将
newtype
,dimap
展开为基础的Profunctor
,然后重新包装起来,而不是弄乱invmap
,通常会更容易看到发生了什么。如何将
Invariant
函子转换为Profunctor
?首先,让我们处理总和与乘积。如果我们可以将f
和g
转换为fp
和gp
的修饰语,那么我们肯定可以将f :+: g
和f :*: g
转换为等效的修饰语总和和乘积。成分呢?有点棘手,但不多。假设我们可以将
f
和g
变成发音器fp
和gp
。现在定义-- Compose f g a ~= ComposeP fp gp a a
newtype ComposeP p q a b = ComposeP (p (q b a) (q a b))
instance (Profunctor p, Profunctor q) => Profunctor (ComposeP p q) where
dimap f g (ComposeP p) = ComposeP $ dimap (dimap g f) (dimap f g) p
现在假设您有一个函数类型;
f a -> g a
。看起来像fp b a -> gp a b
。我认为这应该涵盖大多数有趣的情况。
关于haskell - 如何使用Data.Functor.Invariant?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48708805/