Cam*_*all 14 haskell types composition
我正试图在打"类型俄罗斯方块"方面做得更好.我有这些功能:
(=<<) :: Monad m => (a -> m b) -> m a -> m b
zip :: [a] -> [b] -> [(a, b)]
Run Code Online (Sandbox Code Playgroud)
而GHCi告诉我:
(zip =<<) :: ([b] -> [a]) -> [b] -> [(a, b)]
Run Code Online (Sandbox Code Playgroud)
我很难搞清楚如何从前两个签到最终签名.我的直觉(由于缺乏一个更好的词)是说的第一个参数=<<
,即a -> mb
以某种方式对和解的签名zip
,然后将其都应该从脱落.但我无法理解如何实现这一飞跃.它可以分解为一系列易于遵循的步骤吗?
(zip =<<)
相当于(>>= zip)
,这使得它可能更具可读性.无论哪种方式,正如您正确观察到的那样,zip
占据了(a -> m b)
这些功能中的插槽.
另一个更直观的转变是思考=<<
.它"需要"两个参数,因此如果我们将它应用于一个参数,我们应该只剩下一个参数.因此,签名([b] -> [a]) -> [b] -> [(a, b)]
是一元函数!
(zip =<<) :: ([b] -> [a]) -> ([b] -> [(a, b)])
------------ -----------------
m a' m b'
Run Code Online (Sandbox Code Playgroud)
那是什么m
?Monad实例存在于函数(r ->)
(或者,替代地(->) r
).所以在这种情况下r :: [b]
(因而m :: ([b] ->)
),a' :: [a]
和b' :: [(a, b)]
.
因此,zip
正如我们在开头所断言的那样:
a' -> m b' -- substitute [(a,b)] for b'
a' -> m [(a, b)] -- substitute [a] for a'
[a] -> m [(a, b)] -- substitute ([b] ->) for m
[a] -> ([b] -> [(a,b)])
[a] -> [b] -> [(a,b)]
Run Code Online (Sandbox Code Playgroud)
在其他事情之前做两件事有助于:
x->y->z
变成了x->(y->z)
考虑到这一点,让我们重写类型
(=<<) :: Monad m => (a -> m b) -> (m a -> m b)
zip :: [x] -> ([y] -> [(x, y)])
Run Code Online (Sandbox Code Playgroud)
现在匹配类型.第一个参数=<<
是zip
,所以(a -> m b)
是相同的[x] -> ([y] -> [(x, y)])
.
a -> m b
[x] -> ([y] -> [(x, y)])
Run Code Online (Sandbox Code Playgroud)
所以,a
是[x]
和m b
是([y] -> [(x, y)])
.重写->
前缀表示法,我们得到-> [y] [(x, y)]
,这是相同的(-> [y]) [(x, y)]
.
m b
(-> [y]) [(x, y)]
Run Code Online (Sandbox Code Playgroud)
那m
是(-> [y])
(确实是一个单子)而且b
是[(x, y)]
.
所以现在我们知道什么是什么a
,什么是b
什么,什么是什么m
.让我们(m a -> m b)
用这些术语重写:
(m a) -> (m b)
((-> [y]) [x]) -> ((-> [y]) [(x, y)])
Run Code Online (Sandbox Code Playgroud)
我们再次以中缀风格重写
([y] -> [x]) -> ([y] -> [(x, y)])
Run Code Online (Sandbox Code Playgroud)
这就是变量名称,是GHC给你的答案.