Haskell composition (.) vs F#'s pipe forward operator (|>)
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
).
Related videos on Youtube
Comments
-
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 over 3 yearslihanseys 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 about 14 yearsI agree with the cultural differences. Traditional Haskell makes use of
.
and$
, so people continue to use them. -
Paul Johnson about 14 yearsPoint 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 about 14 yearsInteresting 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 about 14 yearsI 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 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 over 13 yearsHi 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 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 aliasData.Sequence.|>
assnoc
) -
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 almost 13 years
($)
and(|>)
are application not composition. The two are related (as the question notes) but they are not the same (yourfc
is(Control.Arrow.>>>)
for functions). -
Kevin Cantu over 12 yearsIn practice, F#'s
|>
actually reminds me of the UNIX|
more than anything else. -
Khanzor almost 12 yearsNice, so (>>>) is largely equatable to (|>)?
-
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 over 11 yearsas 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 almost 11 yearsI 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 over 8 yearsyes, the culture of reading left to right :) even math should be taught that way...
-
kevinthompson over 8 yearsAnother 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 about 8 years@nicolas left to right is an arbitrary choice. You can get used to right to left.
-
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 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 about 7 yearsCertainly I agree that function composition is legit. By "some F# guys" I'm referring to myself! That my own blog. :P
-
Steven Shaw almost 7 years
>>>
is defined inControl.Category
. -
rmunn about 6 yearsF# also has a composition operator
>>
that is essentially composition in left-to-right reading order. I.e.,let h = f >> g
meanslet 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 tolet chain x = x |> add2 |> mult3 |> add1
, and reads in the same order. -
Jamie over 5 yearsyou can also define infix operators infix :)
x |> f = f x
-
yeshengm over 3 yearsAny reason for Haskell to choose
&
over|>
? I feel like|>
is much more intuitive, and it also reminds me of Unix pipe operator. -
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".