[
Home
]
[ Index:
by date
|
by threads
]
[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
[ 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
> >
> >
> >
> >