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.