关于Haskell中的构图的困惑 [英] Confusion regarding composition in Haskell
问题描述
我正在研究Haskell的书,我意识到我很难理解函数的组成.在最基本的层次上,我有一个管道的心理模型,该模型接受输入并将结果传递给合成中的下一个函数.对于简单的功能,这非常简单.
I'm working through the Haskell book and I've realized I'm having a hard time understanding function composition. At a very basic level I have a mental model of a pipeline that takes an input and passes it's result to the next function in the composition. For simple functions this is very easy.
我遇到的困难是理解组成函数的结果类型签名是如何形成的.例如,如果我们查看elem
的基本定义:
Where I'm having difficulty is understanding how the resulting type signatures of composing the functions come to be. For example, if we look at the base definition of 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
我看不到结果类型签名是如何发生的.如果为我提供了该功能并要求编写类型签名,那我将无可救药.
I fail to see how the resulting type signature occurs. If I were given the function and asked to write the type signature I'd be hopelessly lost.
以下内容也一样.在遍历"一章中,我们告诉我们traverse
只是sequenceA
和fmap
组成的:
The same goes for the following. In the chapter on Traversable we were told that traverse
is just sequenceA
and fmap
composed:
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
的类型签名?
On their own I understand each functions type signature, but how do they combine to create traverse
's type signature?
这里超级迷失了,任何帮助将不胜感激.
Super lost here, any help would be greatly appreciated.
推荐答案
也许仅凭视觉上的对齐方式就可以使您对管道的进展方式有所了解,并帮助您迈向下一个困惑点!
Perhaps merely visually aligning the types will get you part of the way to some intuition about how the pipeline progresses, and help you make progress towards your next point of confusion!
(==) :: Eq a => a -> (a -> Bool)
any :: (a -> Bool) -> (t a -> Bool)
any . (==) :: Eq a => a -> (t a -> Bool)
要在屏幕上保留下一个,我们将Traversable
缩写为T
,将Applicative
缩写为A
.您的问题中还有两个f
,一个在计算级别,一个在类型级别.为避免混淆,我将把您的计算级别f
重命名为g
.因此,如果g :: a -> f b
用于某些Applicative f
:
To keep the next one on one screen, let's abbreviate Traversable
to T
and Applicative
to A
. You also have two f
s in your question, one at the computation level and one at the type level. To avoid confusion, I'm going to rename your computation-level f
to g
instead. So if g :: a -> f b
for some 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 g
,为什么t
的约束是Traversable
而不是Functor
?好的,没问题:我们实际上可以给它一个更宽松的类型fmap g :: Functor t => ...
. Traversable
必须为Functor
,也可以使用这种类型,以使并行性更加清晰.)
(Wait! How come for fmap g
, the constraint on t
is Traversable
and not Functor
? Okay, no problem: we can actually give it the more relaxed type fmap g :: Functor t => ...
. But since every Traversable
must be a Functor
, it can also be given this type which makes the parallels more clear.)
这篇关于关于Haskell中的构图的困惑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!