5

考虑以下 ghci 中的函数定义。

let myF = sin . cos . sum 

在哪里, 。代表两个函数的组合(右结合)。这个我可以打电话

myF [3.14, 3.14]

它给了我想要的结果。显然,它将列表 [3.14, 3.14] 传递给函数“sum”,并将其“结果”传递给 cos 等等。但是,如果我在口译员中这样做

let myF y = sin . cos . sum y 

或者

let myF y = sin . cos (sum y) 

然后我遇到了麻烦。将其修改为以下内容给了我想要的结果。

let myF y = sin . cos $ sum y 

或者

let myF y = sin . cos . sum $ y 

(.) 的类型表明以下形式不应该有问题,因为 'sum y' 也是一个函数(不是吗?毕竟在 Haskell 中一切都是函数?)

let myF y = sin . cos . sum y -- this should work?

更有趣的是,我可以使用两个(或多个)参数(考虑将列表 [3.14, 3.14] 作为两个参数 x 和 y 传递),我必须编写以下内容

let (myF x) y = (sin . cos . (+ x)) y 
myF 3.14 3.14 -- it works! 
let myF = sin . cos . (+) 
myF 3.14 3.14 -- -- Doesn't work!

HaskellWiki 上有一些关于这种形式的讨论,他们称之为“PointFree”形式http://www.haskell.org/haskellwiki/Pointfree。通过阅读这篇文章,我怀疑这种形式不同于两个 lambda 表达式的组合。当我尝试画一条分隔这两种样式的线时,我感到困惑。

4

3 回答 3

10

让我们看看类型。因为我们有sincos

cos, sin :: Floating a => a -> a

对于sum

sum :: Num a => [a] -> a

现在,sum y把它变成一个

sum y :: Num a => a

这是一个值,而不是函数(您可以将其命名为不带参数的函数,但这非常棘手,您还需要命名() -> a函数 -某处对此进行了讨论,但我现在找不到链接-康纳尔谈到了它)。

无论如何,尝试cos . sum y是行不通的,因为.期望双方都有类型a -> bb -> c(签名是(b -> c) -> (a -> b) -> (a -> c))并且sum y不能以这种风格编写。这就是为什么您需要包含括号或$.

至于无点风格,简单的翻译方法是这样的:

  • 带你函数并将函数的最后一个参数移动到由函数应用程序分隔的表达式的末尾。例如,如果mysum x y = x + y我们y最后有但我们现在不能删除它。相反,在mysum x y = (x +) y工作时重写。
  • 删除所述论点。在我们的例子中mysum x = (x +)
  • 重复,直到你没有更多的论点。这里mysum = (+)

(我选择了一个简单的例子,对于更复杂的情况,你必须使用flip和其他)

于 2011-08-02T14:01:38.737 回答
7

不,sum y不是函数。这是一个数字,就像sum [1, 2, 3]是一样。因此,您不能将函数组合运算符(.)与它一起使用是完全有道理的。

并非 Haskell 中的所有内容都是函数。

于 2011-08-02T13:56:52.603 回答
4

强制性的神秘答案是:(空间)比.

Haskell 中的大多数空白可以被认为是一个非常高的固定性$(“应用”函数)。w x . y z基本上是一样的(w $ x) . (y $ z)

当您第一次学习时$.您还应该确保您也了解(空间),并确保您了解语言语义如何以可能(乍一看)不直观的方式隐含地括住事物。

于 2011-08-03T08:11:55.437 回答