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?

7 Answers
7

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

I agree with the cultural differences. Traditional Haskell makes use of . and $, so people continue to use them.
–
AmuckSep 21 '09 at 22:35

8

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.
–
Paul JohnsonSep 22 '09 at 18:28

2

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.
–
Kurt SchelfthoutOct 1 '09 at 15:00

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.

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?
–
The_GhostSep 24 '09 at 13:25

7

(<|) 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.
–
Ganesh SittampalamDec 18 '09 at 8:39

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

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 ($)"
–
mattbhJun 14 '10 at 6:23

1

@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)
–
Nathan SandersJun 14 '10 at 13:21

($) 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
–
gatoatigradoMar 2 '11 at 8:23

1

($) 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).
–
Nathan SandersMar 2 '11 at 16:04

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
–
visMar 17 '12 at 1:38