Version française
Home     About     Download     Resources     Contact us    
Browse thread
Re: [Caml-list] Infix function composition operator
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Jon Harrop <jonathandeanharrop@g...>
Subject: RE: [Caml-list] Infix function composition operator
In OCaml, the value restriction leads to non-generalized type variables ('_a etc.) if you try to define functions like:

# let ( << ) f g x = f(g x);;
val ( << ) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun>

# let cons h t = h::t;;
val cons : 'a -> 'a list -> 'a list = <fun>

# cons << cons;;
- : '_a -> ('_a list -> '_a list) list -> ('_a list -> '_a list) list = <fun>

This is a silly example but you are most likely to hit this problem in practice in the context of parser combinators. Due to JIT compilation, F# cannot relax the value restriction so that does not even compile.

In MLs, you usually want the eta-expanded form:

# let cons2 x = (cons << cons) x;;
val cons2 : 'a -> ('a list -> 'a list) list -> ('a list -> 'a list) list =
  <fun>

But a pipeline is prettier:

# let ( |> ) x f = f x;;
val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun>

# let cons2 x = x |> cons |> cons;;
val cons2 : 'a -> ('a list -> 'a list) list -> ('a list -> 'a list) list =
  <fun>

This is one advantage of Haskell over OCaml/F#. However, I don't see it as a useful advantage in practice because parser combinators are so tedious during development (they require constant attention as types evolve): you want code generation like ocamlyacc or camlp4. OCaml is a very strong contender here, of course.

Cheers,
Jon.

> -----Original Message-----
> From: mark@proof-technologies.com [mailto:mark@proof-technologies.com]
> Sent: 10 November 2010 13:44
> To: jonathandeanharrop@googlemail.com; yminsky@gmail.com;
> arlen@noblesamurai.com
> Cc: caml-list@inria.fr
> Subject: Re: [Caml-list] Infix function composition operator
> 
> So how does value restriction affect things here?  (excuse my lack of
> knowledge)
> 
> One thing about using a pipeline like this is that it relies on '|>'
> being
> left-associative (which it is due to OCaml's convention on operators
> that
> start with "|").
> 
> Mark.
> 
> 
> on 10/11/10 12:52 PM, Jon Harrop <jonathandeanharrop@googlemail.com>
> wrote:
> 
> > A pipeline operator is usually preferred over function composition in
> impure
> > languages like OCaml and F# due to the value restriction. For
> example,
> your
> > example would be written in F# as:
> >
> > x |> op1 |> op2 |> op3 |> op4 |> op5
> >
> > This style is very common in F#, particularly when dealing with
> collections.
> >
> > Cheers,
> > Jon.
> >
> >> -----Original Message-----
> >> From: caml-list-bounces@yquem.inria.fr [mailto:caml-list-
> >> bounces@yquem.inria.fr] On Behalf Of mark@proof-technologies.com
> >> Sent: 10 November 2010 07:00
> >> To: yminsky@gmail.com; arlen@noblesamurai.com
> >> Cc: caml-list@inria.fr
> >> Subject: Re: [Caml-list] Infix function composition operator
> >>
> >> on 10/11/10 3:45 AM, yminsky@gmail.com wrote:
> >>
> >> > This is probably a minority opinion, but I have written and read
> >> quite a
> >> lot
> >> > of OCaml code over the years, and I've seen surprisingly few
> >> effective
> >> uses
> >> > of the composition operator.  Somehow, I usually find that code
> that
> >> avoids
> >> > it is simpler and easier to read.
> >>
> >> I agree that using a composition operator can make the code obtuse,
> and
> >> so
> >> should not be overused.  But it's incredibly useful for certain
> >> situations:
> >>
> >> 1) If you are performing a long chain of composed operations, it
> avoids
> >> nested bracketing piling up.
> >>
> >> For example:
> >>       (op5 <<- op4 <<- op3 <<- op2 <<- op1) x
> >> Instead of:
> >>       op5 (op4 (op3 (op2 (op1 x))))
> >>
> >> This sort of thing happens quite a lot in certain applications, e.g.
> in
> >> language processing, to get at subexpressions.
> >>
> >> 2) Creating an anonymous function to be passed as an argument, it
> >> avoids
> >> explicitly mentioning arguments of that function.
> >>
> >> This sort of thing can happen a lot in functional programming
> >> generally.
> >>
> >> For example:
> >>       List.map (op2 <<- op1) xs
> >> Instead of:
> >>       List.map (fun x -> op2 (op1 x)) xs
> >>
> >> Mark Adams
> >>
> >> _______________________________________________
> >> Caml-list mailing list. Subscription management:
> >> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> >> Archives: http://caml.inria.fr
> >> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> >> Bug reports: http://caml.inria.fr/bin/caml-bugs
> >
> >
> >
> >