haskell - 如何使用Data.Functor.Invariant?

标签 haskell

有人可以给我举个例子吗

invmap :: (a -> b) -> (b -> a) -> f a -> f b  

Invariant 有什么好处?

最佳答案

大多数情况下,人们使用Invariant。您想要这样做的原因是,如果您使用的类型中变量同时出现在协变和逆变位置。

newtype Endo a = Endo {appEndo :: a -> a}
newtype Foo a = Foo (Maybe a -> IO a)
data Bar a = Bar [a] (a -> Bool)

这些都不是仿函数逆变的实例,但它们都可以是不变的实例。

人们很少打扰的原因是,如果您需要对这种类型进行大量映射,通常最好将其分解为协变和逆变部分。每个不变仿函数都可以用 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)

如果您将 newtypedimap 展开到底层 Profunctor 上,然后再次将其包裹起来,通常会更容易看到发生了什么而不是乱搞 invmap

<小时/>

我们如何将Invariant仿函数转换为Profunctor?首先,让我们处理总和和乘积。如果我们可以将fg转为仿函数fpgp,那么我们一定可以将f :+: gf :*: g 转换成等价的仿函数和和积。

作曲怎么样?这有点棘手,但不多。假设我们可以将 fg 转换为仿函数 fpgp。现在定义

-- 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/

相关文章:

java - 你在实际项目中使用过 Quickcheck

haskell - 如何使用 QuickCheck 来测试函数是否终止?

haskell - 'do' 表示法中的新范围

haskell - 在 Haskell 中将元组的元素作为参数提供给函数?

scala - 是否可以延迟遍历具有 O(1) 内存使用的递归数据结构,优化尾调用?

haskell - 如何将多态函数应用于 Either 的两边?

haskell - 如何每秒强制评估 X 次?

haskell - 函数中用递归二叉树列表遍历数据类型

haskell - 列出附加元素的 monad 实例

postgresql - 在haskell中用单反斜杠替换双反斜杠