Why don't we have a composition operator in Pervasives?


#61

“most people agree that straight-forward composition does not actually occur that often”

Maybe because there is no syntax for it, so people are tired of having to define
this function and hence use it less.
Don’t forget that the syntax of the language may influence the style of programmers.

Monads are also rare in OCaml code. Why? Maybe because there is no syntax support for them out_of_the_box_and_without_mangling_with_the_build_system and hence programmers are influenced to not use them.
I just know Lwt and Async as OCaml code bases that have and use monads.

I’ve done some Haskell in the past. I was amazed by the high level code I saw.
There were monads everywhere and using the composition operator was a real pleasure.


#62

I am also amazed at how ‘high level’ Haskell frequently is :slight_smile: I experience emotions very similar to what I feel when someone shows me highly golfed Perl. If some very mild discouragements are enough to keep typical OCaml from looking like typical Haskell, I will be relieved.

That sounds like it’s just a snipe, but it really comes across that you do not think there even exists an opposing position to yours. That there are just people who haven’t connected the dots yet, or who don’t quite understand your position yet, but would understand it if you would beat the drum for a little bit longer. That you are speaking to people who want OCaml to be like Haskell but just haven’t figured out how to do that yet.

I think, when you do understand that an opposition really exists, that you will be more comfortable with a kind of “fine I’ll go build my own treehouse and you’ll all see just how much people prefer it to yours” solution: use, or create, a standard library that offers the compose operator, and encourage the use of it. There’s a whole book that relies on people using an alternative standard library so it’s not something unprecedented.


#63

Actually, both Batteries and Containers define % for function composition. So the only standard library not supporting it is Base/Core.


#64

For the record, (%) is already used in Base/Core for the modulus operation, which to me at least is less confusing.


#65

That’s a shame. OCaml hacked the ‘mod’ keyword as infix specifically as a replacement for (%). I don’t know the history here, but my reasoning is that modulus is a very niche operator that’s rarely used, and therefore doesn’t deserve to occupy a full ASCII symbol that’s easily accessible on the keyboard. I like the idea of re-purposing it for something more useful like composition. Nevertheless, if that’s the way it’s used in Base, it’s fundamentally incompatible and won’t be placed in the standard library. It would still be nice to have composition as a primitive, at the very least.


#66

For me, something named compose or even e.g. comp wouldn’t be very useful on its own, without a matching (ideally single-character) operator. (Too bad about %. :frowning:)


#67

You can always type let (%) = foo into your text editor. In fact, you can define the composition operator yourself in far less time than it takes to read even one reply in this thread.


#68

Yes, I think that’s the best option at present: Define %, or some other operator, at the top of every file where I use it, so that anyone reading the code can scan up and figure out what it means. I still think it would be best to have a standard for a composition operator.

OK! I will refrain from discussing language issues in the future, and just define everything that I want on my own. :slight_smile:


#69

(%) is not completely equivalent to (mod), viz.:

─( 16:42:35 )─< command 0 >──────────────────────────────────────{ counter: 0 }─
utop # open! Core;;
─( 16:42:37 )─< command 1 >──────────────────────────────────────{ counter: 0 }─
utop # (-3) % 5;;
- : int = 2
─( 16:42:39 )─< command 2 >──────────────────────────────────────{ counter: 0 }─
utop # (-3) mod 5;;
- : int = -3

(I find (%)'s behavior generally more useful, e.g., (index - 1) % length.)

This thread has become quite long enough, though :confused:


#72

I did some tests and it seems that with flamba the equivalence between the two idioms is restored. I tested with this functions:

let f x = 
  ignore (Array.create ~len:50 x);
  fun y -> x + y

let f_staged x =
  ignore (Array.create ~len:50 x);
  Staged.stage (fun y -> x + y)

let g x y = x + y

let h x y = x * y

I composed or piped f or g with h and got this results:

  Name                 Time/Run   mWd/Run   Percentage  
 -------------------- ---------- --------- ------------ 
  f composed             3.20ns                  3.51%  
  f with pipe           91.09ns    51.00w      100.00%  
  g composed             3.19ns                  3.50%  
  g with pipe            3.17ns                  3.48%  
  compose with stage     3.19ns                  3.50%  
  pipe with stage        3.18ns                  3.49%

The pipe idiom works well only with functions of the form fun x y -> ... but if we do some heavy computation with x before defining fun y -> ... then we have to stage the result or use the composition idiom.