如何导出此函数的类型:

时间:2019-02-07 08:20:55

标签: haskell types composition

我正在努力提高演奏“俄罗斯方块”的能力。我具有以下功能:

(=<<) :: Monad m => (a -> m b) -> m a -> m b
zip :: [a] -> [b] -> [(a, b)]

GHCI告诉我:

(zip =<<) :: ([b] -> [a]) -> [b] -> [(a, b)]

我很难弄清楚如何从前两个中得出最终的签名。我的直觉(因为缺少更好的词)是说=<<的第一个参数a -> mb在某种程度上与zip的签名相符,因此应该从中脱颖而出。但是我不明白如何实现这一飞跃。可以将其分解为一系列易于遵循的步骤吗?

3 个答案:

答案 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)

在其他所有事情之前做两件事会有所帮助:

  1. 放入显式括号,使x->y->z成为x->(y->z)
  2. 重命名类型变量,以免发生冲突

记住这一点,让我们重写类型

(=<<) :: 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类型,unificationa1 -> m b1[a] -> [b] -> [(a, b)]类型([a] -> ([b] -> [(a, b)]),用完全括号括起来)的结果,因为类型中的->与右侧相关联)。或以全前缀形式

    (->)  a1   ( m            b1       )
    (->)  [a]  ( ((->) [b])   [(a, b)] )