2

第 995 页上的“Haskell Programming from First Principles”的第 16 章有一个练习来手动计算类型检查的方式(fmap . fmap)。它建议将每个类型的类型替换fmap为组合运算符类型中的函数类型:

T1(.) :: (b -> c) -> (a -> b) -> a -> c

T2fmap :: Functor f => (m -> n) -> f m -> f n

T3fmap :: Functor g => (x -> y) -> g x -> g y

通过(尝试)将 T2 和 T3 代入 T1,我得出以下结论:

T4:((m -> n) -> f m -> f n) -> ((x -> y) -> g x -> g y) -> a -> c

此外,它建议检查类型(fmap . fmap)以查看最终类型应该是什么样子。

T5:(fmap . fmap) :: (Functor f1, Functor f2) => (a -> b) -> f1 (f2 a) -> f1 (f2 b)

我无法理解我应该在这里做什么。任何知识渊博的haskellers可以帮助我开始,或者提供类似练习的例子来展示如何手工计算类型?

4

1 回答 1

3

我们一步一步小心翼翼地进行:

--- fmap . fmap  =  (.) fmap fmap
--- Functor f, g, ... => ..... 

(.)      :: (   b     ->      c    ) -> (a ->  b ) -> a ->     c
    fmap ::  (d -> e) -> f d -> f e
             --------    ----------
(.) fmap ::                             (a ->d->e) -> a -> f d -> f e
                                             ----          ----------
-- then,

(.) fmap      :: (   a     ->  d  ->  e ) -> a   -> f   d   -> f   e
         fmap ::  (b -> c) -> g b -> g c
                  --------    ---    ---
(.) fmap fmap ::                          (b->c) -> f (g b) -> f (g c)
                                          ------      -----      -----

重要的是在每次单独使用类型时一致地重命名所有类型变量,以避免混淆。

我们使用箭头在右侧关联的事实,

 A -> B -> C   ~   A -> (B -> C)

并且类型推断规则是

   f   :: A -> B
     x :: C
   --------------
   f x ::      B    ,  A ~ C

(f :: A -> B) (x :: C) :: B在类型的等价/统一A ~ C和它所需要的一切之下。

于 2021-05-17T10:38:09.513 回答