Haskell组合(.)与f#的管道向前算子(|>)

时间:2021-02-17 22:34:00

In F#, use of the the pipe-forward operator, |>, is pretty common. However, in Haskell I've only ever seen function composition, (.), being used. I understand that they are related, but is there a language reason that pipe-forward isn't used in Haskell or is it something else?

在f#中,使用管道向前运算符|>是很常见的。然而,在Haskell中,我只看到过使用的函数组合(.)。我理解它们是相关的,但是有没有语言上的原因使得管道向前在Haskell中不被使用,或者是别的什么?

9 个解决方案

#1


57  

I am being a little speculative...

我有点怀疑……

Culture: I think |> is an important operator in the F# "culture", and perhaps similarly with . for Haskell. F# has a function composition operator << but I think the F# community tends to use points-free style less than the Haskell community.

文化:我认为|>在f#“文化”中是一个重要的操作符,或许与之相似。Haskell。f#有一个函数组合操作符< <但是我认为f#社区比haskell社区更倾向于使用无积分风格。< p>

Language differences: I don't know enough about both languages to compare, but perhaps the rules for generalizing let-bindings are sufficiently different as to affect this. For example, I know in F# sometimes writing

语言差异:我对这两种语言的了解还不够,但也许对于一般化的let-bindings的规则有足够的不同来影响它。例如,我知道在f#中有时写作

let f = exp

will not compile, and you need explicit eta-conversion:

将不会编译,并且您需要显式的etc -conversion:

let f x = (exp) x   // or x |> exp

to make it compile. This also steers people away from points-free/compositional style, and towards the pipelining style. Also, F# type inference sometimes demands pipelining, so that a known type appears on the left (see here).

编译。这也使人们远离无分/合成风格,而转向流水线风格。此外,f#类型推断有时需要流水线操作,以便在左边出现一个已知的类型(参见这里)。

(Personally, I find points-free style unreadable, but I suppose every new/different thing seems unreadable until you become accustomed to it.)

(就我个人而言,我觉得没有分数的风格是不可读的,但我认为在你习惯之前,每一个新的/不同的东西都是不可读的。)

I think both are potentially viable in either language, and history/culture/accident may define why each community settled at a different "attractor".

我认为这两种语言都具有潜在的可行性,而历史/文化/事故可能会解释为什么每个社区都有不同的“吸引人”。

#2


80  

In F# (|>) is important because of the left-to-right typechecking. For example:

在f#(|>)中,由于从左到右的类型检查,所以很重要。例如:

List.map (fun x -> x.Value) xs

generally won't typecheck, because even if the type of xs is known, the type of the argument x to the lambda isn't known at the time the typechecker sees it, so it doesn't know how to resolve x.Value.

一般不会进行类型检查,因为即使x的类型已知,当类型检查器看到x的参数x的类型也不知道,所以它不知道如何解析x. value。

In contrast

与此形成鲜明对比的是

xs |> List.map (fun x -> x.Value)

will work fine, because the type of xs will lead to the type of x being known.

会工作得很好,因为x的类型会导致已知的x的类型。

The left-to-right typechecking is required because of the name resolution involved in constructs like x.Value. Simon Peyton Jones has written a proposal for adding a similar kind of name resolution to Haskell, but he suggests using local constraints to track whether a type supports a particular operation or not, instead. So in the first sample the requirement that x needs a Value property would be carried forward until xs was seen and this requirement could be resolved. This does complicate the type system, though.

由于像x.Value这样的结构涉及名称解析,所以需要从左到右进行类型检查。西蒙•佩顿•琼斯(Simon Peyton Jones)曾写过一份建议,建议向Haskell添加类似的名称解析,但他建议使用本地约束来跟踪类型是否支持特定的操作。所以在第一个样本中,x需要一个值属性的需求将会被继续,直到看到xs,这个需求可以被解决。不过,这确实使类型系统复杂化。

#3


39  

More speculation, this time from the predominantly Haskell side...

更多的猜测,这次来自主要的哈斯卡尔一方……

($) is the flip of (|>), and its use is quite common when you can't write point-free code. So the main reason that (|>) not used in Haskell is that its place is already taken by ($).

($)是(|>)的翻转,当您不能编写无点代码时,它的使用非常普遍。所以(|>)没有在Haskell中使用的主要原因是它的位置已经被($)取代了。

Also, speaking from a bit of F# experience, I think (|>) is so popular in F# code because it resembles the Subject.Verb(Object) structure of OO. Since F# is aiming for a smooth functional/OO integration, Subject |> Verb Object is a pretty smooth transition for new functional programmers.

另外,从一些f#经验来看,我认为(|>)在f#代码中非常流行,因为它类似于OO的Subject.Verb(Object)结构。因为f#的目标是平滑的函数/OO集成,所以Subject |>谓词对象对于新的函数程序员来说是一个非常平滑的过渡。

Personally, I like thinking left-to-right too, so I use (|>) in Haskell, but I don't think many other people do.

就我个人而言,我也喜欢从左到右思考,所以我在Haskell中使用(|>),但我不认为其他人会这么做。

#4


27  

I think we're confusing things. Haskell's (.) is equivalent to F#'s (>>). Not to be confused with F#'s (|>) which is just inverted function application and is like Haskell's ($) - reversed:

我觉得我们把事情搞混了。Haskell的(.)等价于f# 's(>>)。不要混淆f# 's(|>),这是一个反向功能应用程序,就像Haskell的($)-反向:

let (>>) f g x = g (f x)
let (|>) x f = f x

I believe Haskell programmers do use $ often. Perhaps not as often as F# programmers tend to use |>. On the other hand, some F# guys use >> to a ridiculous degree: http://blogs.msdn.com/b/ashleyf/archive/2011/04/21/programming-is-pointless.aspx

我相信Haskell程序员经常使用$ $。也许不会像f#程序员那样经常使用|>。另一方面,有些f#的人使用>>的程度非常荒谬:http://blogs.msdn.com/b/ashleyf/archive//2011/04/21/program-pointless.aspx

#5


16  

Left-to-right composition in Haskell

Some people use left-to-right (message-passing) style in Haskell too. See, for example, mps library on Hackage. An example:

有些人在Haskell中也使用从左到右(消息传递)样式。例如,参见关于Hackage的mps库。一个例子:

euler_1 = ( [3,6..999] ++ [5,10..999] ).unique.sum

I think this style looks nice in some situations, but it's harder to read (one needs to know the library and all its operators, the redefined (.) is disturbing too).

我认为这种样式在某些情况下看起来很不错,但是它很难阅读(需要了解库及其所有操作符,重新定义的(.)也令人不安)。

There are also left-to-right as well as right-to-left composition operators in Control.Category, part of the base package. Compare >>> and <<< respectively:

控件中还有从左到右和从右到左的组合操作符。类别,基本包的一部分。比较>>>和<<<

ghci> :m + Control.Category
ghci> let f = (+2) ; g = (*3) in map ($1) [f >>> g, f <<< g]
[9,5]

There is a good reason to prefer left-to-right composition sometimes: evaluation order follows reading order.

有时喜欢从左到右的作文是有很好的理由的:评价顺序遵循阅读顺序。

#6


16  

If you want to use F#'s |> in Haskell then in Data.Function is the & operator (since base 4.8.0.0).

如果你想在Haskell中使用f#的|>,那么在数据中。函数是&运算符(因为基数为4.8.0.0)。

#7


15  

I have seen >>> being used for flip (.), and I often use that myself, especially for long chains that are best understood left-to-right.

我已经看到>>>被用于flip(.),我经常使用它,特别是对于长链,这是最容易理解的从左到右的。

>>> is actually from Control.Arrow, and works on more than just functions.

>>>实际上来自于控制。箭头,不仅仅是函数。

#8


12  

Aside from style and culture, this boils down to optimizing the language design for either pure or impure code.

除了风格和文化,这可以归结为对纯代码或不纯代码的语言设计进行优化。

The |> operator is common in F# largely because it helps to hide two limitations that appear with predominantly-impure code:

|>操作符在f#中很常见,这主要是因为它有助于隐藏出现在主要不纯代码中的两个限制:

  • Left-to-right type inference without structural subtypes.
  • 没有结构子类型的从左到右类型推断。
  • The value restriction.
  • 值限制。

Note that the former limitation does not exist in OCaml because subtyping is structural instead of nominal, so the structural type is easily refined via unification as type inference progresses.

注意,在OCaml中不存在前面的限制,因为子类型化是结构化的而不是标称的,所以随着类型推断的进展,结构类型很容易通过统一来细化。

Haskell takes a different trade-off, choosing to focus on predominantly-pure code where these limitations can be lifted.

Haskell采用了一种不同的折衷方法,选择将焦点集中在可以解除这些限制的主要纯代码上。

#9


1  

This is my first day to try Haskell (after Rust and F#), and I was able to define F#'s |> operator:

这是我第一次尝试Haskell(在Rust和f#之后),我能够定义f#的|>操作符:

(|>) :: a -> (a -> b) -> b
(|>) x f = f x
infixl 0 |>

and it seems to work:

它似乎起作用了:

factorial x =
  case x of
    1 -> 1
    _ -> x * factorial (x-1)

main =     
    5 |> factorial |> print

I bet a Haskell expert can give you an even better solution.

我打赌Haskell专家会给你一个更好的解决方案。

#1


57  

I am being a little speculative...

我有点怀疑……

Culture: I think |> is an important operator in the F# "culture", and perhaps similarly with . for Haskell. F# has a function composition operator << but I think the F# community tends to use points-free style less than the Haskell community.

文化:我认为|>在f#“文化”中是一个重要的操作符,或许与之相似。Haskell。f#有一个函数组合操作符< <但是我认为f#社区比haskell社区更倾向于使用无积分风格。< p>

Language differences: I don't know enough about both languages to compare, but perhaps the rules for generalizing let-bindings are sufficiently different as to affect this. For example, I know in F# sometimes writing

语言差异:我对这两种语言的了解还不够,但也许对于一般化的let-bindings的规则有足够的不同来影响它。例如,我知道在f#中有时写作

let f = exp

will not compile, and you need explicit eta-conversion:

将不会编译,并且您需要显式的etc -conversion:

let f x = (exp) x   // or x |> exp

to make it compile. This also steers people away from points-free/compositional style, and towards the pipelining style. Also, F# type inference sometimes demands pipelining, so that a known type appears on the left (see here).

编译。这也使人们远离无分/合成风格,而转向流水线风格。此外,f#类型推断有时需要流水线操作,以便在左边出现一个已知的类型(参见这里)。

(Personally, I find points-free style unreadable, but I suppose every new/different thing seems unreadable until you become accustomed to it.)

(就我个人而言,我觉得没有分数的风格是不可读的,但我认为在你习惯之前,每一个新的/不同的东西都是不可读的。)

I think both are potentially viable in either language, and history/culture/accident may define why each community settled at a different "attractor".

我认为这两种语言都具有潜在的可行性,而历史/文化/事故可能会解释为什么每个社区都有不同的“吸引人”。

#2


80  

In F# (|>) is important because of the left-to-right typechecking. For example:

在f#(|>)中,由于从左到右的类型检查,所以很重要。例如:

List.map (fun x -> x.Value) xs

generally won't typecheck, because even if the type of xs is known, the type of the argument x to the lambda isn't known at the time the typechecker sees it, so it doesn't know how to resolve x.Value.

一般不会进行类型检查,因为即使x的类型已知,当类型检查器看到x的参数x的类型也不知道,所以它不知道如何解析x. value。

In contrast

与此形成鲜明对比的是

xs |> List.map (fun x -> x.Value)

will work fine, because the type of xs will lead to the type of x being known.

会工作得很好,因为x的类型会导致已知的x的类型。

The left-to-right typechecking is required because of the name resolution involved in constructs like x.Value. Simon Peyton Jones has written a proposal for adding a similar kind of name resolution to Haskell, but he suggests using local constraints to track whether a type supports a particular operation or not, instead. So in the first sample the requirement that x needs a Value property would be carried forward until xs was seen and this requirement could be resolved. This does complicate the type system, though.

由于像x.Value这样的结构涉及名称解析,所以需要从左到右进行类型检查。西蒙•佩顿•琼斯(Simon Peyton Jones)曾写过一份建议,建议向Haskell添加类似的名称解析,但他建议使用本地约束来跟踪类型是否支持特定的操作。所以在第一个样本中,x需要一个值属性的需求将会被继续,直到看到xs,这个需求可以被解决。不过,这确实使类型系统复杂化。

#3


39  

More speculation, this time from the predominantly Haskell side...

更多的猜测,这次来自主要的哈斯卡尔一方……

($) is the flip of (|>), and its use is quite common when you can't write point-free code. So the main reason that (|>) not used in Haskell is that its place is already taken by ($).

($)是(|>)的翻转,当您不能编写无点代码时,它的使用非常普遍。所以(|>)没有在Haskell中使用的主要原因是它的位置已经被($)取代了。

Also, speaking from a bit of F# experience, I think (|>) is so popular in F# code because it resembles the Subject.Verb(Object) structure of OO. Since F# is aiming for a smooth functional/OO integration, Subject |> Verb Object is a pretty smooth transition for new functional programmers.

另外,从一些f#经验来看,我认为(|>)在f#代码中非常流行,因为它类似于OO的Subject.Verb(Object)结构。因为f#的目标是平滑的函数/OO集成,所以Subject |>谓词对象对于新的函数程序员来说是一个非常平滑的过渡。

Personally, I like thinking left-to-right too, so I use (|>) in Haskell, but I don't think many other people do.

就我个人而言,我也喜欢从左到右思考,所以我在Haskell中使用(|>),但我不认为其他人会这么做。

#4


27  

I think we're confusing things. Haskell's (.) is equivalent to F#'s (>>). Not to be confused with F#'s (|>) which is just inverted function application and is like Haskell's ($) - reversed:

我觉得我们把事情搞混了。Haskell的(.)等价于f# 's(>>)。不要混淆f# 's(|>),这是一个反向功能应用程序,就像Haskell的($)-反向:

let (>>) f g x = g (f x)
let (|>) x f = f x

I believe Haskell programmers do use $ often. Perhaps not as often as F# programmers tend to use |>. On the other hand, some F# guys use >> to a ridiculous degree: http://blogs.msdn.com/b/ashleyf/archive/2011/04/21/programming-is-pointless.aspx

我相信Haskell程序员经常使用$ $。也许不会像f#程序员那样经常使用|>。另一方面,有些f#的人使用>>的程度非常荒谬:http://blogs.msdn.com/b/ashleyf/archive//2011/04/21/program-pointless.aspx

#5


16  

Left-to-right composition in Haskell

Some people use left-to-right (message-passing) style in Haskell too. See, for example, mps library on Hackage. An example:

有些人在Haskell中也使用从左到右(消息传递)样式。例如,参见关于Hackage的mps库。一个例子:

euler_1 = ( [3,6..999] ++ [5,10..999] ).unique.sum

I think this style looks nice in some situations, but it's harder to read (one needs to know the library and all its operators, the redefined (.) is disturbing too).

我认为这种样式在某些情况下看起来很不错,但是它很难阅读(需要了解库及其所有操作符,重新定义的(.)也令人不安)。

There are also left-to-right as well as right-to-left composition operators in Control.Category, part of the base package. Compare >>> and <<< respectively:

控件中还有从左到右和从右到左的组合操作符。类别,基本包的一部分。比较>>>和<<<

ghci> :m + Control.Category
ghci> let f = (+2) ; g = (*3) in map ($1) [f >>> g, f <<< g]
[9,5]

There is a good reason to prefer left-to-right composition sometimes: evaluation order follows reading order.

有时喜欢从左到右的作文是有很好的理由的:评价顺序遵循阅读顺序。

#6


16  

If you want to use F#'s |> in Haskell then in Data.Function is the & operator (since base 4.8.0.0).

如果你想在Haskell中使用f#的|>,那么在数据中。函数是&运算符(因为基数为4.8.0.0)。

#7


15  

I have seen >>> being used for flip (.), and I often use that myself, especially for long chains that are best understood left-to-right.

我已经看到>>>被用于flip(.),我经常使用它,特别是对于长链,这是最容易理解的从左到右的。

>>> is actually from Control.Arrow, and works on more than just functions.

>>>实际上来自于控制。箭头,不仅仅是函数。

#8


12  

Aside from style and culture, this boils down to optimizing the language design for either pure or impure code.

除了风格和文化,这可以归结为对纯代码或不纯代码的语言设计进行优化。

The |> operator is common in F# largely because it helps to hide two limitations that appear with predominantly-impure code:

|>操作符在f#中很常见,这主要是因为它有助于隐藏出现在主要不纯代码中的两个限制:

  • Left-to-right type inference without structural subtypes.
  • 没有结构子类型的从左到右类型推断。
  • The value restriction.
  • 值限制。

Note that the former limitation does not exist in OCaml because subtyping is structural instead of nominal, so the structural type is easily refined via unification as type inference progresses.

注意,在OCaml中不存在前面的限制,因为子类型化是结构化的而不是标称的,所以随着类型推断的进展,结构类型很容易通过统一来细化。

Haskell takes a different trade-off, choosing to focus on predominantly-pure code where these limitations can be lifted.

Haskell采用了一种不同的折衷方法,选择将焦点集中在可以解除这些限制的主要纯代码上。

#9


1  

This is my first day to try Haskell (after Rust and F#), and I was able to define F#'s |> operator:

这是我第一次尝试Haskell(在Rust和f#之后),我能够定义f#的|>操作符:

(|>) :: a -> (a -> b) -> b
(|>) x f = f x
infixl 0 |>

and it seems to work:

它似乎起作用了:

factorial x =
  case x of
    1 -> 1
    _ -> x * factorial (x-1)

main =     
    5 |> factorial |> print

I bet a Haskell expert can give you an even better solution.

我打赌Haskell专家会给你一个更好的解决方案。