GHC如何解释`foldl + 0 [1,2,3]`(括号周围没有括号)?

Fil*_*und 3 haskell types ghc

有一件事,让我早卡住时学习Haskell是之间的差异foldl +foldl (+).

Prelude> :t foldl + 0 [1,2,3]
  :: (Num t1, Num ((b -> a -> b) -> b -> t a -> b),
      Num ([t1] -> (b -> a -> b) -> b -> t a -> b), Foldable t) =>
     (b -> a -> b) -> b -> t a -> b
Run Code Online (Sandbox Code Playgroud)

VS

Prelude> :t foldl (+) 0 [1,2,3]
foldl (+) 0 [1,2,3] :: Num b => b
Run Code Online (Sandbox Code Playgroud)

Haskell/GHC如何得出这种类型foldl + 0 [1,2,3]?我怎么能理解为什么它扩展到这种巨型?

ama*_*loy 8

因为+是一个中缀运算符而没有括号覆盖的东西,

foldl + 0 [1,2,3]
Run Code Online (Sandbox Code Playgroud)

解析为

(foldl) + (0 [1,2,3])
Run Code Online (Sandbox Code Playgroud)

最简单的起点foldl是众所周知的类型(如果你不知道,你可以问GHCI :t foldl).

foldl :: Foldable f => (a -> b -> a) -> a -> f b -> a
Run Code Online (Sandbox Code Playgroud)

接下来,添加的另一面.因为0作为一个函数[1,2,3]作为参数应用,所以必须有一个函数类型的Num实例,它将一些数字类型的列表作为输入,并产生输出......好吧,我们将会这样做.

0 [1,2,3] :: (Num t, Num ([t] -> s)) => s
Run Code Online (Sandbox Code Playgroud)

因为+要应用于这两个表达式,它们必须具有相同的类型.因此,我们必须统一

foldl :: Foldable f => (a -> b -> a) -> a -> f b -> a
Run Code Online (Sandbox Code Playgroud)

0 [1,2,3] :: (Num t, Num ([t] -> s)) => s
Run Code Online (Sandbox Code Playgroud)

最常见的方法是让s它们与foldl(结合它们的约束)完全相同的类型,给予我们

0 [1,2,3] :: (Foldable f,
              Num t, 
              Num ([t] -> (a -> b -> a) -> a -> f b -> a)) 
          => (a -> b -> a) -> a -> f b -> a
Run Code Online (Sandbox Code Playgroud)

请记住,当然foldl必须具有完全相同的类型:

foldl :: (Foldable f, 
          Num t,
          Num ([t] -> (a -> b -> a) -> a -> f b -> a)) 
      => (a -> b -> a) -> a -> f b -> a
Run Code Online (Sandbox Code Playgroud)

因为+来自Num类型类,它们共享的类型也必须是Num.

foldl + 0 [1,2,3] :: (Foldable f, 
                      Num t, 
                      Num ([t] -> (a -> b -> a) -> a -> f b -> a),
                      Num ((a -> b -> a) -> a -> f b -> a))
                  => (a -> b -> a) -> a -> f b -> a
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,模拟一些类型的重命名,正是GHC告诉你的.

但当然,这是一种相当愚蠢的类型.有可能有人会编写所有这些令人发指的Num实例,因此GHC尽职尽责地将其推断为有效类型.但实际上没有人写过这些实例,因此实际使用这个表达式会遇到很多麻烦.你应该做的就是修理你的括号.