haskell - 关于 Haskell 中的组合的困惑

标签 haskell

我正在阅读 Haskell 的书,我意识到我很难理解函数组合。在一个非常基本的层面上,我有一个管道的心理模型,它接受输入并将其结果传递给组合中的下一个函数。对于简单的功能,这很容易。

我遇到困难的地方是理解码成函数的结果类型签名是如何形成的。例如,如果我们查看 elem 的基本定义:

elem :: (Foldable t, Eq a) => a -> t a -> Bool
elem = any . (==)

>:t (==)
(==) :: Eq a => a -> a -> Bool
>:t any
any :: Foldable t => (a -> Bool) -> t a -> Bool

我看不到生成的类型签名是如何发生的。如果给我这个函数并要求我编写类型签名,我会绝望地迷失方向。

下面的情况也是如此。在 Traversable 一章中,我们被告知 traverse只是 sequenceAfmap组成:
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
traverse f = sequenceA . fmap f

>:t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
>:t sequenceA
sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)

我自己理解每个函数的类型签名,但它们如何结合创建 traverse的类型签名?

在这里 super 迷路,任何帮助将不胜感激。

最佳答案

也许仅仅在视觉上对齐类型会让你对管道的进展有一些直觉,并帮助你朝着下一个困惑点前进!

(==)       :: Eq a => a -> (a -> Bool)
any        ::              (a -> Bool) -> (t a -> Bool)
any . (==) :: Eq a => a                -> (t a -> Bool)

要在一个屏幕上保留下一个,我们缩写 TraversableTApplicativeA .您还有两个 f s 在您的问题中,一个在计算级别,一个在类型级别。为避免混淆,我将重命名您的计算级别 fg反而。所以如果 g :: a -> f b对于一些 Applicative f :
fmap g                   ::  T t       =>               t a -> t (f b)
sequenceA                :: (T t, A f) =>                      t (f b) -> f (t b)
sequenceA . fmap g       :: (T t, A f) =>               t a            -> f (t b)
\g -> sequenceA . fmap g :: (T t, A f) => (a -> f b) -> t a            -> f (t b)

(等等!为什么 fmap gt 的约束是 Traversable 而不是 Functor ?好吧,没问题:我们实际上可以给它更宽松的类型 fmap g :: Functor t => ... 。但是由于每个 Traversable必须是 Functor ,也可以使用这种类型,这样可以使相似之处更加清晰。)

关于haskell - 关于 Haskell 中的组合的困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53725329/

相关文章:

multithreading - 如何从 fork 线程安全地使用 WebKitGTK?

c++ - 生成给定长度的所有可能的 1 和 0 数组的算法

haskell - 我可以教 GHC 数学归纳法吗?

haskell - 我如何告诉 runhaskell 模块不在同一个文件夹中?

haskell - 用折叠连接两个列表定义

c# - 对比 C# 泛型与 Haskell 参数化类型

haskell - 如何让函数 [a] -> [a] 对 [(a,Int)] 进行操作?

haskell - curry (==) 是如何工作的?

multithreading - 从线程本身内部取消异步线程

performance - 加速 Haskell PBKDF2 算法