【问题标题】:Why doesn't Haskell accept arguments after a function composition?为什么 Haskell 在函数组合后不接受参数?
【发布时间】:2014-12-18 13:01:18
【问题描述】:

考虑到 Haskell 有柯里化函数,我们可以这样做:

foo a b = a + b -- equivalent to `foo a = \b -> a + b`

foo 1 -- ok, returns `\b -> 1 + b`
foo 1 2 -- ok, returns 3

声明函数返回 lambda,就像在注释中一样,也可以正常工作。

但是当我编写这些函数时,像这样:

foo a b = a + b
bar x = x * x

bar . foo 1 -- ok, returns a lambda
bar . foo 1 2 -- wrong, I need to write `(bar . foo 1) 2`

然后它会导致错误。

问题是:为什么函数组合周围的括号是必要的?

【问题讨论】:

  • 呃,什么错误?我们不知道错误是什么!放在这里。
  • “没有因使用‘print’而导致 (Show (a0 -> c0)) 的实例”。实际上,这并不是真正的错误。我是说使用bar . foo 1 2 不能按我的意愿工作。
  • 但是组合运算符只得到两个参数并返回一个 lambda,好吗?为什么它不能作为正常功能工作?
  • 为什么从函数返回 lambda 不像函数组合那样工作?我的意思是,在组合中我需要在一个括号周围加上括号,并且当从函数返回 lambda 时不需要括号。 你的问题不清楚......哪个 函数你指的是什么?
  • @Thelost A lambda IS 一个正常的函数!完全没有区别。

标签: haskell lambda higher-order-functions


【解决方案1】:

假设您在 GHCi 中定义了以下内容:

λ> let foo a b = a + b
λ> let bar x = x * x

根据your follow-up comments的部分内容,看来你相信

bar . foo 1 2

等价于

(bar . foo 1) 2

但是,请记住,函数应用程序(空格)的优先级高于组合运算符(.);因此

bar . foo 1 2

真的等价于

bar . ((foo 1) 2)

现在,让我们看看类型:

  • . 的类型为 (b -> c) -> (a -> b) -> a -> c;它的两个参数是函数(可以组合)。
  • bar 具有 Num a => a -> a 类型,因此与 . 的第一个参数的类型 (b -> c) 兼容。
  • foo 1 2 的类型为 Num a => a;它是一个(多态)数值常量,不是一个函数,因此.的第二个参数的类型(a -> b)兼容。李>

这就是您在bar . foo 1 2 中收到类型错误的原因。但是,您可以做的是

bar $ foo 1 2

因为$ 运算符的类型为(a -> b) -> a -> b。见Haskell: difference between . (dot) and $ (dollar sign)

【讨论】:

  • @Thelost 澄清一下:你是在问为什么(bar . foo 1) 2 有效而bar . foo 1 2 无效?请注意,如果您定义了foo a = \b -> a + b,那么bar . foo 1 2 仍然不起作用...
  • 没错!这是我的问题。查看 Haskell 的规则,函数只能接收一个参数。然后,我认为 Haskell 会寻找这个:bar . foo 1 2 并说 foo 正在接收 1,并返回一个 lambda。因此,组合发生在这里:bar . foo 1 并让2 退出。
  • @Thelost No. bar . foo 1 2 相当于bar . ((foo 1) 2)不是,正如你所想的那样,相当于(bar . foo 1) 2。函数应用程序(空格)具有更高的优先级,因此作为第二个参数传递给. 的是foo 1 2 的值。
【解决方案2】:

bar . foo 1 2bar . (foo 1 2) 不是 (bar . foo 1) 2

这里没有什么神秘的事情与 lambdas 相关。假设我们将foo 的应用扩展为1:

bar . foo 1 2
bar . (\b -> 1 + b) 2

现在,我们将 lambda 应用于 2

bar . 3

还有你的问题。

相反,如果我们正确放置括号,我们会像这样评估它:

(bar . foo 1) 2
(bar . (\b -> 1 + b)) 2
(\x -> bar ((\b -> 1 + b) x)) 2
bar 3

【讨论】:

  • 这不是在回答 “为什么不返回 lambda...”的问题
  • @AJFarmar 我试着更清楚地说明为什么这不是问题。
猜你喜欢
  • 2011-01-15
  • 2015-08-21
  • 2021-09-30
  • 1970-01-01
  • 2011-12-28
  • 2022-09-23
  • 1970-01-01
  • 2020-03-31
  • 1970-01-01
相关资源
最近更新 更多