Haskell函数组合(正向管道) - 为什么这样做?

sea*_*ear 20 haskell

在下面的代码中,fibseq表示来自Fibonacci序列的数字序列.(从代码中解决Project Euler#2)

我已经定义了一个中缀函数|>:

(|>) x y = y x.
Run Code Online (Sandbox Code Playgroud)

这让我可以执行以下操作(如unix管道):

take 34 fibseq |> filter even |> filter (< 4000000) |> sum
Run Code Online (Sandbox Code Playgroud)

我的问题是,为什么这有效?

我本以为 take 34 fibseq |> filter even应该转换成filter (take 34 fibseq) even,(我认为)会导致类型错误.

相反,它似乎正在转变为filter even (take 34 fibseq)哪些作品并且是我想要的,但我不明白它为什么会起作用.

sth*_*sth 24

函数应用程序(filter even比)比任何运算符都更紧密,所以你的代码相当于:

(take 34 fibseq) |> (filter even) |> (filter (< 4000000)) |> sum
Run Code Online (Sandbox Code Playgroud)


Ant*_*sky 8

这是因为运算符优先级.函数应用程序运算符,并置或 (the space), has the highest precedence, so take 34 fibseq |> filter even解析为((take 34) fibseq) |> (filter even),相当于(filter even) ((take 34) fibseq); 因为函数应用程序是左关联的,所以这相当于filter even (take 34 fibseq).

通常,任何二元运算符都可以优先使用固定性声明,例如

infixl 0 |> 
infixr 9 .
Run Code Online (Sandbox Code Playgroud)

lr说,操作是否是左或右结合(即,是否a • b • c团作为(a • b) • ca • (b • c)); number - 0到9之间的整数 - 指定优先级.数字越大意味着优先级越高(应用程序的有效优先级为∞); 例如,*/具有优先权7,和+-具有优先权6.要检查在ghci中操作者的优先级,只需要输入:info $(或无论哪个操作者)在提示.

并且作为一个注释:您的代码将起作用,但这不是我通常会编写它的方式.如果你很好奇,在Haskell中,我会用$运算符编写代码,运算符只执行函数应用但优先级低:filter even $ take 34 fibseq.如果我有更多的函数要应用,我会使用合成运算符:fun1 arg1 . fun2 . fun3 arg2 arg3 . filter even $ take 34 fibseq.它以另一种方式读取,但它通常是您在Haskell中找到的.