我正在努力提高演奏“俄罗斯方块”的能力。我具有以下功能:
(=<<) :: Monad m => (a -> m b) -> m a -> m b
zip :: [a] -> [b] -> [(a, b)]
GHCI告诉我:
(zip =<<) :: ([b] -> [a]) -> [b] -> [(a, b)]
我很难弄清楚如何从前两个中得出最终的签名。我的直觉(因为缺少更好的词)是说=<<
的第一个参数a -> mb
在某种程度上与zip
的签名相符,因此应该从中脱颖而出。但是我不明白如何实现这一飞跃。可以将其分解为一系列易于遵循的步骤吗?
答案 0 :(得分:8)
(zip =<<)
等效于(>>= zip)
,这可能会使它更具可读性。无论哪种方式,zip
都会占据这些功能的(a -> m b)
插槽,就像您已经正确观察到的那样。
要进行的另一种直观转换是考虑=<<
的多样性。它“采用”两个参数,因此,如果将其应用于一个参数,则只应再加上一个。因此,签名([b] -> [a]) -> [b] -> [(a, b)]
是一元函数!
(zip =<<) :: ([b] -> [a]) -> ([b] -> [(a, b)])
------------ -----------------
m a' m b'
那么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)]
答案 1 :(得分:7)
在其他所有事情之前做两件事会有所帮助:
x->y->z
成为x->(y->z)
记住这一点,让我们重写类型
(=<<) :: Monad m => (a -> m b) -> (m a -> m b)
zip :: [x] -> ([y] -> [(x, y)])
现在匹配类型。 =<<
的第一个参数是zip
,因此(a -> m b)
与[x] -> ([y] -> [(x, y)])
相同。
a -> m b
[x] -> ([y] -> [(x, y)])
所以a
是[x]
,而m b
是([y] -> [(x, y)])
。用前缀符号重写->
,我们得到-> [y] [(x, y)]
,与(-> [y]) [(x, y)]
相同。
m b
(-> [y]) [(x, y)]
所以m
是(-> [y])
(实际上是单子),而b
是[(x, y)]
。
所以现在我们知道什么是a
,什么是b
和什么是m
。让我们用以下术语重写(m a -> m b)
:
(m a) -> (m b)
((-> [y]) [x]) -> ((-> [y]) [(x, y)])
再次以infix样式重写,我们得到
([y] -> [x]) -> ([y] -> [(x, y)])
最多包含变量名,这与GHC给您的答案相同。
答案 2 :(得分:3)
您只需将它们一个接一个地写下来,以垂直对齐为辅助,同时一致地重命名类型变量,这样就不会意外捕获:
(=<<) :: Monad m => (a1 -> m b1 ) -> m a1 -> m b1
zip :: [a] -> ([b] -> [(a, b)])
[a] -> ([b] ->) [(a, b)]
[a] -> (->) [b] [(a, b)]
-----------------------------------------------------------
a1 ~ [a] , m ~ (->) [b] , b1 ~ [(a, b)] (*)
-----------------------------------------------------------
(zip =<<) :: Monad m => m a1 -> m b1
((->) [b]) a1 -> ((->) [b]) b1
([b] -> a1) -> ([b] -> b1)
([b] -> [a]) -> ([b] -> [(a, b)])
([b] -> [a]) -> [b] -> [(a, b)]
提供了Monad ((->) [b])
实例。它是做什么的:
> :i Monad
class Monad (m :: * -> *) where
.......
instance Monad ((->) r) -- Defined in `GHC.Base'
如果在函数monad的特定情况下遵循类型,我们可以看到(g =<< f) x == g (f x) x
,依此类推
(zip =<<) f xs = zip (f xs) xs
,从中更容易查看其类型的含义。
(*)
是substitution类型,unification是a1 -> m b1
和[a] -> [b] -> [(a, b)]
类型([a] -> ([b] -> [(a, b)])
,用完全括号括起来)的结果,因为类型中的->
与右侧相关联)。或以全前缀形式
(->) a1 ( m b1 )
(->) [a] ( ((->) [b]) [(a, b)] )