Wednesday, December 13, 2017

Defining backticks using "pipe" operations

(Thanks to Simon Fowler and others on the Links team for the discussion leading to this...)

In Haskell, you can use a 2-argument function as if it were an infix operator by putting "backticks" around it like this:

ghci> let plus x y = x + y
ghci> 1 `plus` 2
3

In a number of functional languages such as F# and OCaml, the following "pipe" operations have become popular (I'll continue using Haskell syntax, though):

ghci> let (|>) x f = f x
ghci> let (<|) f x = f x
ghci> [1,2,3] |> map (plus 1)
[2,3,4]



With the above definitions, the "backtick" behavior is definable:

ghci> 1 |>plus<| 2
3

What's going on here: the above code is parsed as

(1 |> plus) <| 2

So first, we evaluate (1 |> plus), which is defined as (plus 1), i.e. a partial application of plus.  So we have

(plus 1) <| 2

Then this is defined as (plus 1) 2, i.e. now plus is fully applied and we can evaluate it as 1+2 = 3.

Warning: This relies in a somewhat hacky way on the default left-associativity of infix operators in Haskell. You get different results if you explicitly parenthesize like this

1 |> (plus <| 2)

(or if |> and <| were defined as right-associative), at least if the underlying operation is noncommutative.

Labels: ,

3 Comments:

At December 13, 2017 7:09 pm , Blogger Gabriel Scherer said...

This is a nice trick, that I learned from David Rajchenbach-Teller for the first time in 2008: https://caml.inria.fr/pub/ml-archives/caml-list/2008/04/65b363e470d6af3832df96930c59e5d6.en.html

 
At December 13, 2017 7:17 pm , Blogger James Cheney said...

Thanks. Sorry, I should have been more careful... I wasn't claiming to have (re)discovered this trick! It was already being used in the Links source code (in OCaml), possibly inspired by the same observation you made above, for all I know.

The interesting fact(oid) I wanted to call attention to was that the two infix operators that simulate Haskell-style backticks are exactly the pipe operators now being commonly used in F# and friends... in fact, in the Links source code in OCaml (up until yesterday) we were using the same symbols, but with the opposite of their "pipe" meaning, leading to confusion. We now use them as described above, and so there is no need to define another pair of infix operators!

 
At December 13, 2017 7:22 pm , Blogger James Cheney said...

In fact it looks like the Links code has used this trick since circa 2006... I'm sure it must have been known before that. https://github.com/links-lang/links/blame/2965f1476766ccac15c347d79b0aef8cb40bba18/utility.ml

 

Post a Comment

Subscribe to Post Comments [Atom]

Links to this post:

Create a Link

<< Home