Haskell composition (.) vs F#'s pipe forward operator (|>)

25,958

Solution 1

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.

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 f = exp

will not compile, and you need explicit eta-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).

(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".

Solution 2

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

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.

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.

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.

Solution 3

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 ($).

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.

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

Solution 4

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:

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

Solution 5

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

Share:
25,958

Related videos on Youtube

Ben Lings
Author by

Ben Lings

Nothing

Updated on July 08, 2022

Comments

  • Ben Lings
    Ben Lings over 1 year

    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?

    • itmuckel
      itmuckel over 3 years
      lihanseys answer states that & is Haskell's |>. Buried deep in this thread and took me a few days to discover. I use it a lot, because you naturally read left to right to follow your code.
  • Amok
    Amok about 14 years
    I agree with the cultural differences. Traditional Haskell makes use of . and $, so people continue to use them.
  • Paul Johnson
    Paul Johnson about 14 years
    Point free is sometimes more readable than pointful, sometimes less. I generally use it in the argument to functions like map and filter, to avoid having a lambda cluttering things up. I sometimes use it in top-level functions too, but less often and only when its something straightforward.
  • The_Ghost
    The_Ghost about 14 years
    Interesting this is that there is (<|) operator similar to (.) in Haskell with the same direction of data right-to-left. But how will work type resolution for it?
  • Salma b
    Salma b about 14 years
    I don't see much culture in it, in the sense that there simply isn't much of a choice in the matter as far as F# is concerned (for the reasons you and Ganesh mention). So I'd say that both are viable in Haskell, but F# is definitely much better equipped for using the pipeline operator.
  • GS - Apologise to Monica
    GS - Apologise to Monica almost 14 years
    (<|) is actually similar to Haskell's ($). Left-to-right typechecking is only required for resolving things like .Value, so (<|) works fine in other scenarios, or if you use explicit type annotations.
  • mattbh
    mattbh over 13 years
    Hi Nathan, is "flip ($)" predefined anywhere in the Haskell platform? The name "(|>)" is already defined in Data.Sequence with another meaning. If not already defined, what do you call it? I'm thinking of going with "($>) = flip ($)"
  • Nathan Shively-Sanders
    Nathan Shively-Sanders over 13 years
    @mattbh: Not that I can find with Hoogle. I didn't know about Data.Sequence.|>, but $> looks reasonable to avoid conflicts there. Honestly, there are only so many good-looking operators, so I would just use |> for both and manage conflicts on a case-by-case basis. (Also I would be tempted to just alias Data.Sequence.|> as snoc)
  • gatoatigrado
    gatoatigrado almost 13 years
    ($) just redefines the parsing associativity. It's not the same as forward composition -- you have to have names bound in scope. Try it yourself: pastebin.com/uEc2k612
  • Nathan Shively-Sanders
    Nathan Shively-Sanders almost 13 years
    ($) and (|>) are application not composition. The two are related (as the question notes) but they are not the same (your fc is (Control.Arrow.>>>) for functions).
  • Kevin Cantu
    Kevin Cantu over 12 years
    In practice, F#'s |> actually reminds me of the UNIX | more than anything else.
  • Khanzor
    Khanzor almost 12 years
    Nice, so (>>>) is largely equatable to (|>)?
  • sastanin
    sastanin almost 12 years
    @Khanzor Not exactly. (|>) applies an argument, (>>>) is mostly function composition (or similar things). Then I suppose there is some fixity difference (didn't check it).
  • vis
    vis over 11 years
    as you say it's like Haskell's $ operator - reversed, you can also easily defined it as: a |> b = flip ($) which becomes equivalent to F#'s pipeline e.g. you can then do [1..10] |> map f
  • Dobes Vandermeer
    Dobes Vandermeer almost 11 years
    I think (.) the same as (<<), whereas (>>) is the reverse composition. That is ( >> ) : ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3 vs ( << ) : ('T2 -> 'T3) -> ('T1 -> 'T2) -> 'T1 -> 'T3
  • nicolas
    nicolas over 8 years
    yes, the culture of reading left to right :) even math should be taught that way...
  • kevinthompson
    kevinthompson over 8 years
    Another benefit of |> in F# is that it has nice properties for IntelliSense in Visual Studio. Type |>, and you get a list of functions that can be applied to the value on the left, similar to what happens when typing . after an object.
  • Martin Capodici
    Martin Capodici about 8 years
    @nicolas left to right is an arbitrary choice. You can get used to right to left.
  • nicolas
    nicolas about 8 years
    @MartinCapodici indeed. some people go top to bottom then right to left. it's all relative and arbitrary, and we can adapt to everything, but that's a pain
  • Florian F
    Florian F about 7 years
    -1 for "use >> to a ridiculous degree". (Well, I didn't but you got my point). F in F# is for "functional", so function composition is legitimate.
  • AshleyF
    AshleyF about 7 years
    Certainly I agree that function composition is legit. By "some F# guys" I'm referring to myself! That my own blog. :P
  • Steven Shaw
    Steven Shaw almost 7 years
    >>> is defined in Control.Category.
  • rmunn
    rmunn about 6 years
    F# also has a composition operator >> that is essentially composition in left-to-right reading order. I.e., let h = f >> g means let h x = x |> f |> g. This allows you to write function composition that looks like the |> pipeline, but in point-free style: let chain = add2 >> mult3 >> add1 is equivalent to let chain x = x |> add2 |> mult3 |> add1, and reads in the same order.
  • Jamie
    Jamie over 5 years
    you can also define infix operators infix :) x |> f = f x
  • yeshengm
    yeshengm over 3 years
    Any reason for Haskell to choose & over |>? I feel like |> is much more intuitive, and it also reminds me of Unix pipe operator.
  • Marcel Besixdouze
    Marcel Besixdouze over 3 years
    @yeshengm I find & very intuitive. Code nearly reads correctly in English by just pronouncing & as "and". For example: 5 & factorial & show reads aloud as "take 5 and then take factorial of it and then apply show to it".

Related