Haskell composition (.) vs F#'s pipe forward operator (|>)
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.
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".
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.