2017-05-27 51 views
2

在最近的工作表上,我被要求解释为什么函数f,在:f g x = g (g x) x中没有类型。对Haskell函数类型参数的说明

对于Haskell,我很新,我很困惑于如何在不知道任何有关函数的细节的情况下计算出左右表达式的关联顺序。好像是g应该被定义为:

g :: a -> b,假设的x类型为a - 然而,这似乎立即导致麻烦的,因为在RHS,g (g x) x似乎暗示g需要两个参数,类型之一ba之一。此外,我也坚持如何阅读LHS,也就是说f有两个参数:函数g和变量x,或者它只需要1个参数,(g x)

我想知道是否有人可以指导我如何阅读这些表达式?

+0

我无法理解所问的问题。你能否准确地向我们提出与工作表中出现的问题一样的问题?我可以说'g(g x)'将'g'应用于'x'的结果是'g'。如果你对使用括号的应用程序的语言更熟悉,那么这些语言就是'g(g(x))'。 –

+0

@ReinHenrichs问题如下:“解释为什么下面定义的函数f没有类型: f g x = g(g x)x” 我有点好奇你怎么能解决这个问题?一旦我们评估g(g x),将g应用于g x的结果,我们将如何处理x(g(g x)x? – CowNorris

+0

啊,我错过了最后的'x'并且感到困惑,因为'f g x = g(g x)'显然是一个类型。 –

回答

6

相关的规则是:

  1. 应用写成并置,即f x适用fx

  2. 括号用于界定表达式,不适用于功能应用,即f (g x)适用fg x。 (其中g x是本身的g应用到x。)

  3. 应用相关联的左侧,即,f x y = (f x) y

把这些在一起,我们可以看到,g (g x) x = (g (g x)) x,即,g (g x)应用到x,其中g (g x)是本身的gg x到该应用程序。

我还应该提到,Haskell中的所有函数都只有一个参数。似乎一个函数具有多个参数在哪里,实在是哗众取宠:

f x y z = ((f x) y) z 

换句话说,f是一个函数,参数,返回一个函数,参数,返回一个函数,参数并返回一个值。你可能会明白为什么我们有时更喜欢撒谎,并说一个函数需要多个参数,但这在技术上并不正确。 “接受多个参数”的函数实际上是一个返回函数的函数,该函数可能会返回一个函数,依此类推。

7

为了能够回答这样的问题,您需要像Haskell编译器一样思考。我们有一个功能。

f g x = g (g x) x 

为了使这是很好类型的,我们需要找到的类型fgx。现在,f需要两个参数,所以

f :: a -> b -> c 
g :: a 
x :: b 

我们也知道,g x必须合理的表达(我们会说g x是“中规中矩”),所以g必须到x可以是函数应用。所以它也是这样的情况,

g :: b -> t0 

其中t0是一个类型变量,现在。我们不知道g x的结果;我们只知道它“有意义”。现在,外部g (g x) x也必须有意义。因此,g必须是我们可以应用g x(其类型为t0,正如我们前面所述)和x(其类型为b)以便能够获得c(函数的返回类型)的结果。所以

g :: t0 -> b -> c 

现在,这里是问题发生的地方。我们看到g有三个声明:ab -> t0t0 -> b -> c。为了使g拥有所有这三种类型,他们必须将统一为。也就是说,通过插入某些变量的值,他们必须能够变得相同。 a没有任何问题,因为它是一个自由变量,不依赖于其他任何东西,所以我们可以将它“设置”为任何我们想要的。因此b -> t0t0 -> b -> c必须相同。在Haskell中,我们写的

(b -> t0) ~ (t0 -> b -> c) 

括号(中种)都是右结合的,所以这相当于

(b -> t0) ~ (t0 -> (b -> c)) 

为了两个函数类型是一样的,他们的论据必须是一样的,所以

b ~ t0 
t0 ~ (b -> c) 

通过的传递特性,这意味着

b ~ (b -> c) 

所以b是一种以自己为论点的类型。这就是Haskell所说的无限类型,不符合现行标准。所以为了让你写的这个函数可以接受,b必须是Haskell中不存在的类型。因此,f不是有效的Haskell函数。

+0

最好不要给作业问题的答案。学生应该回答它,而不是我们。 –

+3

我认为问题和答案在https://meta.stackoverflow.com/q/334822/625403的作业政策指导方针中都是合理的。这当然不是“不利于学生学习的答案”。当然,它比OP可能更理想,但Stack Overflow是为那些从Google来到这里的人创造持久价值的答案,而不仅仅是提出问题的人。 – amalloy

5
  1. 功能应用程序是左结合:a b c解析作为(a b) c
  2. 函数定义对于lambda表达式语法糖:f x y = ...装置f = \x y -> ...
  3. lambda表达式使用多个参数自动咖喱:\x y -> ...装置\x -> (\y -> ...)

因此

f g x = g (g x) x 

意味着

f = \g -> (\x -> (g (g x)) x) 

现在,让我们试着得出的f类型。让我们给它一个名字:

f :: ta 

但究竟什么是taf被定义为的λ,所以它的类型涉及->(它是一个函数):

\g -> (\x -> (g (g x)) x) :: tb -> tc 
g :: tb 
\x -> (g (g x)) x :: tc 

即对于某些类型tbtc,并且g(参数)的类型是tb,并且结果(函数体)的类型是tc\g -> ...的类型是tb -> tc

而且因为整个事情是必然f,我们有

ta = tb -> tc 

我们不tc做,虽然:

\x -> (g (g x)) x :: td -> te 
x :: td 
(g (g x)) x :: te 

tc = td -> te 

功能正文(其类型我们称为te)由一个应用程序组成(必须是)变量x的函数。由此可以得出:

g (g x) :: td -> te 

因为

x :: td 
(g (g x)) x :: te 

再次向下钻取,我们有

g :: tf -> (td -> te) 
g x :: tf 

因为应用gg x必须有类型td -> te。最后,

g :: td -> tf 

因为

x :: td 
g x :: tf 

现在我们有g两个等式:

g :: tf -> (td -> te) 
g :: td -> tf 

因此

tf  = td 
td -> te = tf 

tf -> te = tf 

在这里,我们碰到一个问题:tf定义在之中ms本身,给出类似于

tf = (((((... -> te) -> te) -> te) -> te) -> te) -> te 

即无限大的类型。这是不允许的,这就是为什么f没有有效的类型。