40

Just a quick question. I'm wondering if there is a infix function composition operator in OCaml defined in the standard library (or in Jane Street's Core or in Batteries) like the (.) function in Haskell which saves us a lot parentheses since we can write (f . g . h) x instead of the less appealing f (g (h x))).

Thanks folks.

Stas
  • 11,571
  • 9
  • 40
  • 58
tfboy
  • 947
  • 1
  • 10
  • 14

6 Answers6

31

The answer here is the same as for flip :-). Function composition isn't defined in the OCaml standard library. In this case, it isn't something I miss once in a while, I miss it all the time.

The OCaml Batteries Included project defines function composition (in the order you give) using the operator -| in the BatStd module. As lukstafi points out (see below), this operator will apparently change to % in a future release of Batteries. (I've verified this in their source tree.)

As far as I can see, the Jane Street Core project doesn't define a function composition operator. It defines a function compose in the Fn module.

hugomg
  • 68,213
  • 24
  • 160
  • 246
Jeffrey Scofield
  • 65,646
  • 2
  • 72
  • 108
  • 3
    Thank you Jeffrey. You've been so helpful. I also haven't got access to their documentation at the moment. Following your information, I've found anyway a `compose` function in the source file of Jane Street's Core.Std.Fn (c.f. https://github.com/janestreet/core/blob/master/lib/fn.mli, line 31). Thank you. – tfboy May 19 '13 at 17:02
  • FYI this is their traditional link for docs but it is down: https://ocaml.janestreet.com/ocaml-core/latest/doc/ – rgrinberg May 19 '13 at 22:08
  • (Thanks; I'm waiting to see if it comes back up or if maybe there's a new link instead.) – Jeffrey Scofield May 19 '13 at 22:14
  • 1
    The operators in [Batteries are changing](https://github.com/ocaml-batteries-team/batteries-included/blob/master/src/batPervasives.mliv), see my [earlier answer](http://stackoverflow.com/questions/14410953/converting-f-pipeline-operators-to-ocaml/14414310#14414310). – lukstafi May 20 '13 at 03:14
  • I had the same problem looking for docs, they just never built them in the structure of their package tree. The new version released this morning has docs included though. – nlucaroni May 20 '13 at 15:53
  • As pointed out by @mookid below, the standard library now supports the `(@@)` operator for function composition! It was added in 4.01. – Dan Becker Mar 19 '16 at 05:53
  • 7
    The `@@` operator is not function composition. `@@` has this type: `('a -> 'b) -> 'a -> 'b`. Function composition has this type: `('a -> 'b) -> ('c -> 'a) -> 'c -> 'b`. In fact @mookid mentions that infix composition is discouraged (something I never heard about). For what it's worth, SML has function composition as an infix operator `o`. – Jeffrey Scofield May 22 '16 at 18:27
  • btw `%` there is no `BatStd` module at present, but `%` is available e.g. after executing `open Batteries`. – Mars Jun 28 '17 at 18:02
18

I just want to add that the operator is fairly easy to include, in F# it's simply defined as:

let (<<) f g x = f(g(x));;

which has the type signature: val ( << ) : f:('a -> 'b) -> g:('c -> 'a) -> x:'c -> 'b doing exactly what you need...

(f << g << h) x = f(g(h(x))

so you don't need the batteries project if you don't have to

I'd like to add that the reason it looks like << is, as you might guess, because the >> operator does the opposite:

let (>>) f g x = g(f(x));;

(f >> g >> h) x = h(g(f(x))
Electric Coffee
  • 11,733
  • 9
  • 70
  • 131
  • That's great. In OCaml, `>>` operator works perfectly. However, the `<<` operator completely hangs the interpreter. Why do you think this is? – Ben Sidhom Nov 17 '13 at 22:42
  • 1
    I tested both definitions above, and I don't see any evidence for your claim. If you want a good answer you'll have to post a full question with some example code. – Jeffrey Scofield Nov 17 '13 at 23:13
  • 1
    It looks like a token acceptance error. I defined the operators as above and `let f = (+) 1` and `let g = (*) 3`. At the REPL, `(f >> g) 10` is `33`. However, `(f << g) 10` apparently does not allow the interpreter to process the input because the `<<` token is bad (I had formerly thought that the REPL had hung but noticed the parse error when I tried to compile it from a file). This may be a result of `<<` being a reserved keyword (http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#sec72), but for some reason `>>` works (for now). I'm running OCaml 4.01.0. – Ben Sidhom May 13 '14 at 09:25
  • @BenSidhom, what I posted was just an example; you can just as easily use any other keyword I just used the F# ones because there's documentation on how they work. – Electric Coffee May 13 '14 at 10:21
  • 1
    I know, I was able to get it working by just using a different operator symbol. I was just confused as to why these strange problems were occurring. I imagine F# does not have issues with these symbols. – Ben Sidhom May 13 '14 at 17:07
  • Nah, it goes around that by using `<<<` and `>>>` for bit-shifting instead of `<<` and `>>` like you normally see. The website you linked said `<<` and `>>` should be avoided for compatibility reasons. F# is a fairly isolated language; and as such doesn't have to worry about compatibility – Electric Coffee May 14 '14 at 07:44
  • There's now a very beginner friendly video demonstrating this method for ReasonML https://youtu.be/qZo-VWjC7es – Albin Oct 10 '18 at 01:13
  • Is not the real question about function composition, what the compiler (here, ocamlopt) will make of it? Writing points free composition functions is fun and elegant - but at what cost? And how good is the compiler when it comes to loop fusion? (``x |> List.map f1 |> List.map f2`` optimized to ``x |> List.map (f1 >> f2)`` with all the benefits? – BitTickler Oct 17 '18 at 01:48
17

There is Fn.compose function in Core, but it is not an infix operator. Also, it is implemented as a regular function and has runtime overhead.

In practice, it is pretty convenient to use pipe operator. It has no runtime overhead as implemented directly in compiler (starting from 4.00). See Optimized Pipe Operators for more details.

Pipe operator is available as '|>' in Core. So, you can rewrite your expression as following: h x |> g |> f

malthe
  • 1,237
  • 13
  • 25
Stas
  • 11,571
  • 9
  • 40
  • 58
  • 2
    Some people think the single pipe operator `|>` of Core is a good choice because it simplifies the number of infix operators you have to remember. In theory, you can have function composition and pipe operators, each in forward and reverse, so 4 total. But does that really help? Some view it as overkill and prefer having just `|>`. – Ashish Agarwal May 21 '13 at 14:02
12

The use of an infix composition operator seems to be discouraged. (see this discussion).

You can write f @@ g @@ h x instead of f (g (h x))).

mookid
  • 1,132
  • 11
  • 19
3

In Containers (yet another stdlib replacement for Ocaml), the function composition operator is called % and can be found in the CCFun module:

open Containers
open Fun

let is_zero n = (n = 0)

let nonzeros = List.filter (not % is_zero) [0;1;2;3;0]
dfeuer
  • 48,079
  • 5
  • 63
  • 167
hugomg
  • 68,213
  • 24
  • 160
  • 246
2

Maybe that could help you.

let identite f = f
let (>>) = List.fold_right identite

test:

# let f=fun x-> x+1 and
      g=fun x-> x*2 and
      h=fun x-> x+3;;

# [f;g;h] >> 2;;
- : int = 11
V. Michel
  • 1,599
  • 12
  • 14