(\xyz -> (xy) z) 的手动推断类型

eve*_*hav 3 lambda haskell types

我想了解如何手动获取此 Haskell 表达式的正确类型。

(\x y z -> (x y) z)
Run Code Online (Sandbox Code Playgroud)

一般来说,我大致了解如何手动确定正确的类型,但对于 lambda 表达式,我完全感到困惑。

Zet*_*eta 7

有一种快速获取类型的方法和一种缓慢的方法。缓慢的方式在下面,不会删除任何不必要的括号。

快速方式(对于功能)

让我们记住 Haskell 函数的属性,即

f :: a -> b -> c
Run Code Online (Sandbox Code Playgroud)

这两个f x y(f x) y是相同的,因为a -> b -> ca -> (b -> c)

因此\x y z -> (x y) z与 相同\x y z -> x y z。因此,如果y's 和z's 类型 whereabresp.,则x's 类型是a -> b -> c

\x y z -> x y z :: (a -> b -> c) -> a -> b -> c
Run Code Online (Sandbox Code Playgroud)

如果我们命名该函数,那么我们会这样写:

f :: (a -> b -> c) -> a -> b -> c
f x y z = x y z
Run Code Online (Sandbox Code Playgroud)

甚至更简单:

f :: (a -> b -> c) -> a -> b -> c
f = id
Run Code Online (Sandbox Code Playgroud)

因为它是一个函数类型的识别函数。您可以添加左右括号a -> b -> c中的类型看,由于a -> b -> ca -> (b -> c)

f :: (a -> b -> c) -> (a -> b -> c)
f = id
Run Code Online (Sandbox Code Playgroud)

“慢”的方式

让我们首先为 lambda 命名。这将使我们能够使用类型签名并从那里继续:

f = \x y z -> (x y) z
Run Code Online (Sandbox Code Playgroud)

接下来,我们使用常规函数语法而不是 lambda 语法:

f :: A -> B -> C -> D
f x y z = (x y) z
Run Code Online (Sandbox Code Playgroud)

现在,我们需要弄清楚ABCD。由于x应用于y,我们注意到它A必须是某种函数类型,例如B -> ...?。接下来我们注意到它x y也必须是一个函数。因此,A需要是B -> G,并且G需要再次成为一个函数。由于G能够使用z,因此是一个 type 值C,我们知道它GG = C -> D

f :: (B -> (C -> D)) -> B -> C -> D
Run Code Online (Sandbox Code Playgroud)

我们现在有x的类型,它是B -> (C -> D)。由于既不约束y也不z约束,我们现在可以将所有类型占位符更改为类型变量并最终得到:

f :: (b -> (c -> d)) -> b -> c -> d
f x y z = (x y) z
Run Code Online (Sandbox Code Playgroud)

最后一步,让我们重命名这些变量:

f :: (a -> (b -> c)) -> a -> b -> c
f x y z = (x y) z
Run Code Online (Sandbox Code Playgroud)

这就是\x y z -> (x y) z类型:(a -> (b -> c)) -> a -> b -> c