Is there an infix function composition operator in OCaml?
Asked Answered
B

6

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.

Bloodthirsty answered 19/5, 2013 at 16:45 Comment(0)
D
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.

Dawdle answered 19/5, 2013 at 16:52 Comment(9)
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. github.com/janestreet/core/blob/master/lib/fn.mli, line 31). Thank you.Bloodthirsty
FYI this is their traditional link for docs but it is down: ocaml.janestreet.com/ocaml-core/latest/docHowlet
(Thanks; I'm waiting to see if it comes back up or if maybe there's a new link instead.)Dawdle
The operators in Batteries are changing, see my earlier answer.Jackstraws
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.Alveolate
As pointed out by @mookid below, the standard library now supports the (@@) operator for function composition! It was added in 4.01.Explicit
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.Dawdle
btw % there is no BatStd module at present, but % is available e.g. after executing open Batteries.Kilometer
I agree that @@ isn't function composition. Anyway, here's the link to the documentation: ocaml.org/api/Stdlib.html#VAL(@@)Midge
R
20

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))
Remittance answered 6/10, 2013 at 23:3 Comment(8)
That's great. In OCaml, >> operator works perfectly. However, the << operator completely hangs the interpreter. Why do you think this is?Telencephalon
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.Dawdle
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 (caml.inria.fr/pub/docs/manual-ocaml/lex.html#sec72), but for some reason >> works (for now). I'm running OCaml 4.01.0.Telencephalon
@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.Remittance
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.Telencephalon
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 compatibilityRemittance
There's now a very beginner friendly video demonstrating this method for ReasonML youtu.be/qZo-VWjC7esNitrile
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?Agminate
E
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

Elstan answered 20/5, 2013 at 12:39 Comment(1)
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 |>.Frustration
N
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))).

Neel answered 12/10, 2015 at 17:34 Comment(0)
K
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]
Kwabena answered 19/8, 2016 at 8:1 Comment(0)
G
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
Granniah answered 12/10, 2015 at 23:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.