【问题标题】:How does (fmap.fmap) sum Just [1,2,3] type check in Haskell?(fmap.fmap) 如何在 Haskell 中求和 Just [1,2,3] 类型检查?
【发布时间】:2020-05-04 13:14:23
【问题描述】:

我不明白这个简单的表达式类型在 Haskell 中是如何检查的

(fmap.fmap) sum Just [1, 2, 3]

fmap的组合类型为:

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

所以我期望 f1 ~ List 和 f ~ Maybe,这意味着函数的类型应该是 Integer -> b。但是如果在 ghci 中对它进行类型检查,我会得到:

t (fmap.fmap) _ Just [1, 2, 3]

<interactive>:1:13: error:
    • Found hole: _ :: [Integer] -> b
      Where: ‘b’ is a rigid type variable bound by
               the inferred type of it :: Maybe b at <interactive>:1:1
    • In the first argument of ‘fmap . fmap’, namely ‘_’
      In the expression: (fmap . fmap) _ Just [1, 2, 3]

我看到 ghci 将函数的类型推断为 [Integer] -> b。这怎么可能?

【问题讨论】:

标签: haskell


【解决方案1】:

没有理由期待f1 ~ [] 和f ~ Maybe。请注意,您需要Just :: f (f1 a)。我们知道Just :: a -&gt; Maybe a。因此,实际上是f ~ (-&gt;) a 和f1 ~ Maybe。然后你有

fmap . fmap :: (a -> b) -> (a -> Maybe a) -> a -> Maybe b
--             ^^sum^^^    ^^^^^Just^^^^^    ^ [1, 2, 3]

既然我们知道[1, 2, 3] :: a,我们现在可以推导出a ~ [Integer](默认Numeric 类型为Integer)。

fmap . fmap :: ([Integer] -> b) -> ([Integer] -> Maybe [Integer]) -> [Integer] -> Maybe b

【讨论】:

    【解决方案2】:

    对于后代,这里有一个提示,告诉您如何在未来解决这种问题。您可以使用通配符询问 ghci 中子表达式的类型(只要您没有启用 PartialTypeSignatures)。

    :t ((fmap :: _) . (fmap :: _)) sum Just [1, 2, 3]
    

    这告诉您外部fmap 用于(a1 -&gt; b) -&gt; ([a] -&gt; a1) -&gt; [a] -&gt; b 类型,而内部(a1 -&gt; b) -&gt; Maybe a1 -&gt; Maybe b 类型使用。应该清楚的是,内部fmap 只是作用于Maybe。外部的fmap 乍一看看起来更复杂,但它是(.) 类型的实例化,即函数阅读器函子中的fmap。

    (.)  :: ( y -> z) -> (  x ->  y) ->   x -> z
    fmap :: (a1 -> b) -> ([a] -> a1) -> [a] -> b
    
    x ~ [a]
    y ~ a1
    z ~ b
    

    这里的函子是 ([a] -&gt;),在实际代码中拼写为 (-&gt;) [a],因为 Haskell 不允许类型级别的运算符部分。

    这告诉您外部是(.),您可以从那里逐步内联定义以查看如何评估它。

    (fmap . fmap) sum Just [1, 2, 3]
    fmap (fmap sum) Just [1, 2, 3]
    (.) (fmap sum) Just [1, 2, 3]
    (fmap sum . Just) [1, 2, 3]
    fmap sum (Just [1, 2, 3])
    

    为了减少噪音并避免必须处理这么多类型变量来确定哪些是相关的,您可以使用类型签名修复一些类型,这里是 Int 而不是 Num a =&gt; a。

    :t ((fmap :: _) . (fmap :: _)) sum Just [1 :: Int, 2, 3]
    

    这为(-&gt;) [Int] 函子中的外部fmap 提供(a -&gt; b) -&gt; ([Int] -&gt; a) -&gt; [Int] -&gt; b,在Maybe 中为内部fmap 提供(a -&gt; b) -&gt; Maybe a -&gt; Maybe b。

    为了好玩,反过来,您也可以将(.) 替换为fmap!

    fmap fmap fmap sum Just [1, 2, 3]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-24
      • 2017-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多