Previous week Up Next week

Hello

Here is the latest Caml Weekly News, for the week of April 11 to 18, 2006.

I will be away for two weeks with very limited internet access, so there might be no CWN for two weeks.

  1. Dynamic binding library
  2. ocamlopt, windows, and no console
  3. Announcing OMake 0.9.6.9
  4. Menhir mailing list and new release
  5. dump in camlimages
  6. release 3.09.2
  7. lablgtk2: receiving messages from network?
  8. Generic print function
  9. OCaml interface to WordNet
  10. recursion/iterator question

Dynamic binding library

Archive: http://thread.gmane.org/gmane.comp.lang.caml.general/32720/focus=32720

Oleg announced:
Dynamic binding adds expressiveness; as Luc Moreau emphasized, it is,
when used in moderation, quite useful: for parameterizing a function
deep in the code without changing the interface of all callers; for
propagating the environment information like the current working
directory, printing-depth, etc.  Dynamic binding is inescapable in
mobile code or continuation-based web servers. Dynamic binding, in
some restricted form, is already present in OCaml: exception handlers
are dynamically bound by the 'handle' form. This message announces the
availability of general dynamic binding. This is joint work with
Chung-chieh Shan and Amr Sabry.

Dynamic binding is implemented as a regular library (dependent on the
delimited continuations library announced earlier on this list).  No
changes to the OCaml system and no code transformations are required;
(parts of the) code that do not use dynamic variables incur no
overhead and run at the same speed as before. Here's the interface:

type 'a dynvar
val dnew : unit -> 'a dynvar

   Given a dynvar, a value and a thunk, evaluate the thunk in the dynamic
   environment extended with the binding of the given value to the
   given dynvar
val dlet : 'a dynvar -> 'a -> (unit -> 'w) -> 'w

   Dereferencing: obtain the value associated with the dynvar
   by the closest dynamically-enclosing dlet
val dref : 'a dynvar -> 'a

   Mutation: obtain the current value of the dynvar and change that
   value to the given one. This `mutation' has the effect only
   within the dynamic scope of the latest dlet
val dset : 'a dynvar -> 'a -> 'a

   Given a dynvar and a function, apply the function to the current
   value of the dynvar, and return the result. The application
   is evaluated in the dynamic environment _outside_ of the
   closest dynamically-enclosing dlet.
val dupp : 'a dynvar -> ('a -> 'w) -> 'w

Our dynamic variables are mutable (cf. fluid-variables in many Scheme
systems); mutations however are visible only within the scope of the
dlet statement where they occurred. Here's the simple example

let test12 =
  let p = dnew () in
  dlet p 1 (fun () ->
    let v1 = dref p in
    let v2 = dlet p 2 (fun () ->
      let v3 = dset p 12 in
      let v4 = dref p in
      (v3,v4)) in
    let v5 = dref p in
    (v1,v2,v5))

which yields (1, (2, 12), 1). The function 'dupp' is an extension of
the conventional dynamic binding. It lets us obtain not only the
current binding to the dynamic variable, but any of the previous
bindings as well. In general, we can fold over the execution stack as
if it were a list (please see the 'nub' example in the test code
below).

Because dynamic binding is implemented in terms of delimited
continuations, the two features harmoniously interact. We can use
dynamic variables in shift-based, cooperative threads. At thread
creation time, the user can `designate' some existing dynamic
variables to be private to the thread; the rest are inherited from the
parent. New dynamic variables and new bindings automatically become
thread-private, so the above designation is accomplished with just
dlet.  Mutation and rebinding of private dynamic variables have effect
only in the corresponding thread. Mutations to shared variables are
visible to everyone. Likewise, a re-parameterization of a dynamic
variable in the parent thread is visible in all child threads sharing
that variable. Such partial inheritance of dynamic environment among
threads is an often desired feature; luckily, it is inherent in our
design and thus available `for free'. The end of the test code
vdynvar.ml demonstrates the partial inheritance among the parent and
two cooperatively run threads.

The implementation is surprisingly, short. In particular,

let dref p      = shift p (fun f -> fun v -> f v v)
let dset p newv = shift p (fun f -> fun v -> f v newv)
let dupp p g    = shift p (fun f -> fun y -> f (g y) y)

with dlet taking not much longer.

        http://pobox.com/~oleg/ftp/ML/dynvar.mli
        http://pobox.com/~oleg/ftp/ML/dynvar.ml
The test code:
        http://pobox.com/~oleg/ftp/ML/vdynvar.ml
The dependency:
   http://pobox.com/~oleg/ftp/Computation/Continuations.html#caml-shift
      

ocamlopt, windows, and no console

Archive: http://thread.gmane.org/gmane.comp.lang.caml.general/32711/focus=32711

Jonathan Roewen asked and Dmitry Bely answered:
> How does one generate an .exe using ocamlopt that doesn't launch a
> console window?

What Ocaml build are you using? If Mingw one then I am afraid it's not
possible, but if it's MSVC-based I would try to play with

-cclib /link -cclib /subsystem:windows

options.
      
Igor Peshansky suggested:
In MinGW, you should be able to pass in the -mwindows flag to gcc (see
http://www.mingw.org/docs.shtml).
      
Jonathan Roewen said and Harry Chomsky answered:
> > -cclib /link -cclib /subsystem:windows
>
> Indeed I was scanning the options, and found those. The problem is
> that when you use that, you have to use WinMain instead...

You can use the linker flag "/entry:mainCRTStartup" alongside the 
"/subsystem:windows" flag to achieve what you want: an executable with no 
console but using main() as the starting point.  That's what my OCaml-Win32 
library does when you link the tiny file lkwinapp.obj into your application. 
There's some discussion of the pros and cons of this approach in the 
build.txt file.  If you're curious, the library is available at:

http://www.speakeasy.org/~hchomsky/ocaml-win32.html
      
David Allsopp suggested:
One other option is to change the startup mode of the executable after
compiling and linking it. I did this years ago with <cough> Visual Basic to
make true console applications (the reverse of your problem). I can't find
the code archive, but IIRC it involves changing a single byte in the PE
header that indicates the subsystem to use. The concept of main and winmain
come entirely from C - the actual entry point of your image is independent
of its subsystem so this gets around your linking problem.

I can't get at the machine with the archive of the tool I wrote for doing
this at the moment <sigh>. However, Microsoft have some utilities for doing
this although I don't know whether they will only work for programs
generated with their compiliers - google for Visual Basic's Link utility and
MSVC++'s editbin tool.
      

Announcing OMake 0.9.6.9

Archive: http://thread.gmane.org/gmane.comp.lang.caml.general/32732/focus=32732

Aleksey Nogin announced:
We are proud to announce the latest release of the OMake Build System -
OMake version 0.9.6.9.

OMake is a build system designed for scalability and portability. It 
uses a syntax similar to make utilities you may have used, but it 
features many additional enhancements, including the following.

   - Support for projects spanning several directories or directory
     hierarchies.

   - Fast, reliable, automated, scriptable dependency analysis using MD5
     digests, with full support for incremental builds.

   - Fully scriptable, includes a library that providing support for
     standard tasks in C, C++, OCaml, and LaTeX projects, or a mixture
     thereof.

     Often, a configuration file is as simple as a single line

     .DEFAULT: OCamlProgram(prog, foo bar baz)

     which states that the program "prog" is built from the files foo.ml,
     bar.ml, and baz.ml. This one line will also invoke the default
     standard library scripts for discovering implicit dependencies in
     OCaml files.

   - Full native support for rules that build several files at once.

   - Portability: omake provides a uniform interface on Linux/Unix
     (including 64-bit architectures), Win32, Cygwin, Mac OS X, and other
     platforms that are supported by OCaml.

   - Built-in functions that provide the most common features of programs
     like grep, sed, find, and awk. These are especially useful on Win32.

   - Active filesystem monitoring, where the build automatically restarts
     whenever you modify a source file. This can be very useful during
     the edit/compile cycle.

   - A built-in command-interpreter osh that can be used interactively.

OMake preserves the style of syntax and rule definitions used in 
Makefiles, making it easy to port your project to OMake. There is no 
need to code in Perl (cons), or Python (scons). However, there are a few 
things to keep in mind:

  1. Indentation is significant, but tabs are not required.
  2. The OMake language is functional: functions are first-class and
     there are no side-effects apart from I/O.
  3. Scoping is dynamic.

OMake is licensed under a mixture of the GNU GPL license (OMake engine 
itself) and the MIT-like license (default configuration files).

OMake version 0.9.6.9 in minor bugfixes/feature enhancements release. 
The changes in this version include:

    - Significantly improved C++ support; minor improvements in OCaml
      support.
    - Significantly updated the default (sample) OMakefile.
    - Significantly improved the performance of the built-in find
      command.
    - Several other bug fixes and improvements.
    - A number of documentation fixes and improvements.

For a more verbose change log, please visit 
http://omake.metaprl.org/changelog.html#0.9.6.9 .

Source and binary packages of OMake 0.9.6.9 may be downloaded from 
http://omake.metaprl.org/download.html (Windows and OS X binaries are 
not there yet,  but should become available soon). In addition, OMake 
may be obtained via the GODI packaging system (release lines "3.08", 
"3.09" and "dev").

To try it out, run the command "omake --install" in a project directory, 
and modify the generated OMakefile.

OMake 0.9.6.9 is still an alpha release.  While we have made an effort 
to ensure that it is bug-free, it is possible some functions may not 
behave as you would expect.  Please report any comments and/or bugs to 
the mailing list omake@metaprl.org and/or at http://bugzilla.metaprl.org/
      

Menhir mailing list and new release

Archive: http://thread.gmane.org/gmane.comp.lang.caml.general/32736/focus=32736

Francois Pottier announced:
I would like to announce the existence of a mailing list for announcements and
discussion of issues related to Menhir, the LR(1) parser generator for
Objective Caml.

The Web interface to the mailing list is at

  http://yquem.inria.fr/cgi-bin/mailman/listinfo/menhir-list

I would also like to announce a new release of Menhir. The most prominent
change is that the conflict explanations even got better: comparing derivation
trees is made easier by factoring out a greatest common factor. The new
release is available via GODI or via the Web at

  http://pauillac.inria.fr/~fpottier/menhir/
      

dump in camlimages

Archive: http://thread.gmane.org/gmane.comp.lang.caml.general/32727/focus=32727

Jonathan Roewen asked and Jun Furuse answered:
> Quick question :)
> 
> Do the dump functions in the camlimages library basically create a
> string equivalent to an RAW image file?

Quick answer :)

Yes. 

RGBRGB... stream for 24bit-depth image for example. Size is equal to
3 x width x height.
      
Florent Monnier added:
(maybe you don't mind, but just in case)
there are such features in OCaml/ImageMagick too.
you can load all the image data (in jpg, png, raw, etc..) in a string (which 
is usefull for exemple to send an image to a web browser from a cgi-bin)

you can get all the data in a BigArray too for direct exchange of data between 
ImageMagick and OCaml (which feature is only available in the devel version 
of the binding yet)
      

release 3.09.2

Archive: http://thread.gmane.org/gmane.comp.lang.caml.general/32740/focus=32740

Damien Doligez announced:
It is our pleasure to announce the availability of OCaml version 3.09.2.

This is mainly a bug-fix release, with only one big new feature: the  
port
to Mac OS X on Intel processors.

See below for a list of changes with respect to 3.09.1.

It is currently available in source form at
http://caml.inria.fr/pub/distrib/ocaml-3.09/ and it will shortly be
added to our Web page at http://caml.inria.fr/ocaml/release.en.html,
where binary packages will soon be available.

-- The OCaml team

Bug fixes:
- Makefile: problem with "make world.opt" PR#3954
- compilers: problem compiling several modules with one command line  
PR#3979
- compilers,ocamldoc: error message that Emacs cannot parse
- compilers: crash when printing type error PR#3968
- compilers: -dtypes wrong for monomorphic type variables PR#3894
- compilers: wrong warning on optional arguments PR#3980
- compilers: crash when wrong use of type constructor in let rec PR#3976
- compilers: better wording of "statement never returns" warning PR#3889
- runtime: inefficiency of signal handling PR#3990
- runtime: crashes with I/O in multithread programs PR#3906
- camlp4: empty file name in error messages PR#3886
- camlp4: stack overflow PR#3948
- otherlibs/labltk: ocamlbrowser ignores its command line options  
PR#3961
- otherlibs/unix: Unix.times wrong under Mac OS X PR#3960
- otherlibs/unix: wrong doc for execvp and execvpe PR#3973
- otherlibs/win32unix: random crash in Unix.stat PR#3998
- stdlib: update_mod not found under Windows PR#3847
- stdlib: Filename.dirname/basename wrong on Win32 PR#3933
- stdlib: incomplete documentation of Pervasives.abs PR#3967
- stdlib: Printf bugs PR#3902, PR#3955
- tools/checkstack.c: missing include
- yacc: crash when given argument "-" PR#3956

New features:
- ported to MacOS X on Intel PR#3985
- configure: added support for GNU Hurd PR#3991
      

lablgtk2: receiving messages from network?

Archive: http://thread.gmane.org/gmane.comp.lang.caml.general/32749/focus=32749

Ivan Matveich asked:
I'm writing a gtk program that must receive data through a tcp
connection and react to it immediately.

What's the best way to implement this?
Can gtk call me back when data is available on a socket?
How do I use Marshal without blocking?
      
Markus Mottl suggested:
You can set the socket options Unix.SO_RCVTIMEO and Unix.SO_SNDTIMEO
using Unix.setsockopt_float, passing the number of seconds until
timeout as argument.
      
Eric Cooper also suggested:
You can use the Glib.IO interface to create a glib io_channel from
your TCP socket, and then use add_watch to associate a callback with
it.  Your socket will then be polled as part of the Glib main event loop.
      
Remi Vanicat also suggested:
As someone already tell you, you could use the Glib.IO interface.
There is also equeue of Gerd Stolpman that is integrated with the Gtk
main loop, see
http://www.ocaml-programming.de/programming/equeue.html
      
Ivan Matveich then asked and Jacques Garrigue answered:
> Thanks, module Glib.Io is what I needed.
> 
> Now I have another question. I've started writing some code,
> 
> module Channel =
>   struct
>     type event =
>       | Connected of Unix.sockaddr
>       | Dropped of Unix.sockaddr
>       | Received of Unix.sockaddr * x
>       | Sent of Unix.sockaddr * x
>     type action =
>       | Associate of Unix.sockaddr
>       | Dissociate of Unix.sockaddr
>       | Send of Unix.sockaddr * x
> 
> where x will be something returned by Marshal.from_string.
> 
> How do I properly specify its type?

I suppose x should be Obj.t, meaning that you're going to use Obj.repr
and Obj.obj. This is clearly unsafe, but any use of Marshal is.
      

Generic print function

Archive: http://thread.gmane.org/gmane.comp.lang.caml.general/32760/focus=32760

Oleg announced:
The facility that prints results and types of expressions evaluated at
the top-level is now available anywhere in the program -- in bytecode-
or natively compiled programs. Generic printing is a (perhaps
unintentional) `side-effect' of MetaOCaml -- of the fact that a code
value is not merely AST; the code value also captures the type and the
type environment of variables and other values. Generic printing is a
library that works with the unmodified MetaOCaml (which is _fully_
compatible with the regular OCaml).

MOTIVATION

First of all, there is an, arguably small, matter of print_int,
print_char, etc.  Most of the time the typechecker knows exactly what
is the type of the data to print. Why should we spell it out in the
suffix of 'print' (or as a format specifier in Printf).

This small annoyance gets bigger if we deal with a complex data
structure, such as a list of records whose elements are variants and
arrays. There is no built-in print_xxx function for it: we _have to_
write our own. What is annoying is that OCaml knows darn well how to
print the structure, if the structure is the result of an expression
evaluated at top level. Alas, such printing is _not_ available in
standalone programs, or if we want to use the print function somewhere
in the code, where the structure is produced as an intermediate
result. Such a printing is a useful debugging aid. We may also want to
use the printing facility to write out the data structure, in a
human-readable form, into various files. The top-level output is quite
pretty and is useful beyond the top level.

INTERFACE and SIMPLE EXAMPLE

The core function is
    val fprint : Format.formatter -> ('a,'b) code -> string 
which takes a code value of any type, and pretty-prints it on the
given formatter. The printed result is exactly the same as that by
the top-level value printing. The function [fprint] returns the
representation of the expression's type, as a string. The latter
is arguably a frill, but it was easy to do, so just as well.

For example,

    let pr_type et = Format.printf "\n%s <at> ." et

    let () = 
      let x = Some ([|(10,true);(11,false)|]) in 
      pr_type (print .<x>.)

prints the following two lines:

       Some [|(10, true); (11, false)|]
       (int * bool) array option

The first line is the value, and the latter (printed by pr_type)
is the type. There was no need to define any custom printer for the
value or its components. A more involved examples is 65 lines down
in this message.

AVAILABILITY

        http://pobox.com/~oleg/ftp/ML/gprint/

The included Makefile builds bytecode and native gprint libraries,
and runs the validation test vgprint.ml -- at the top-level
(no need to compile any library), in a byte-code executable,
and a native code executable.

        The implementation depends on the unmodified MetaOCaml.  To
compile the library, MetaOCaml distribution is required. The
implementation is surprisingly simple and can be easily integrated
with MetaOCaml. http://www.metaocaml.org/

DESIGN

MetaOCaml lets us manipulate pieces of code as values. Whereas 1 is an
int value, .<1>. is a code value, of the type ('a,int) code. MetaOCaml
can print those code values:

     # let x = 1 in Trx.npc .<x>.;;
     .<1>.
     # let x = 'a' in Trx.npc .<x>.;;
     .<'a'>.
so far, so good. However,

     # let x = "a" in Trx.npc .<x>.;;
    .<(* cross-stage persistent value (as id: x) *)>.
And here we hit the snag. If we use a different printing function,
     # let x = "a" in Trx.printcode .<x>.;;
     expression ([0,0+-1]..[0,0+-1]) ghost
     Pexp_cspval <compiled_code> (as id: "x")

we see that the code value is internally an AST, Parsetree.expression.
We also see that aside from a few simple cases, MetaOCaml does not
inline the values from the captured variables; rather, MetaOCaml
incorporates references to such variables (so-called, cross-stage
persistent (CSP) variables).

We need the second observation: the code value is intended to be
evaluated (i.e., `run'). The compilation of a code value generally
requires its type. For example, to compile [match x with Foo -> ...]
we need to know the type of [x]. In particular, we need to know if
[Foo] is the only variant. If so, the above match is exhaustive and we
do not need to compile the default case: [_ -> raise Match_error].
Therefore, when MetaOCaml captures the reference to a CSP variable, it
has to, in general, capture the type as well. And it does, in a
special AST node, which contains the corresponding
Typedtree.expression. The latter includes the type and the
type environment with declarations, etc. These are
exactly the data that top-level's generic print function needs.

The common, and correct, reply to the frequently asked question as
to why OCaml does not have generic print is follows: printing a value
requires the knowledge of its type. Indeed, a machine integer '1' may
represent, inter alia, both an integer 0 and a boolean 'false'. The
type information is not preserved in the compiled code. Fortunately,
MetaOCaml's code values do preserve the necessary type information.

COMPLEX EXAMPLE

Let us first define the following complex data type:

module C = struct
  type 'a color = Blue | Green | Rgb of 'a
end;;

type 'a image = {title : string; pixels : 'a C.color array};;
type big = int image list;;

let v = [
  {title = "im1";
   pixels = [| C.Blue; C.Rgb 10 |]};
  {title = "im2";
   pixels = [| C.Green |]};
]

The following expression
    let () = pr_type (print .<v>.)
prints exactly what we expect.

Before continuing the example, we should note a drawback of the current
lack of integration of the generic print facility with MetaOCaml.  When
doing [print .<x>.] where x is of a variant type and its current value
is a constant constructor (e.g., None), we see the output 
'(* cross-stage persistent value (as id: x) *)'. This is a drawback of
some optimizations in MetaOCaml, and will be fixed if this code is
integrated into MetaOCaml. Fortunately, there is an easy workaround:
replace [print .<x>.] with [print (let z = [x] in .<z>.)].

We now continue the example:

open C
let some_processing ims =
  let brighten px =
      let new_px = match px with
                    Blue  -> Green
                  | Green -> Rgb 10
                  | Rgb x -> Rgb (x+1) in
      let () = Format.printf " <at> .pixel: %a -> %a  <at> ."
               (fun ppf v -> ignore (fprint ppf v))
               (let x = [px] in .<x>.)
               (fun ppf v -> ignore (fprint ppf v))
               (let x = [new_px] in .<x>.) in
      new_px in
  let process im =
    let () = Format.printf "Processing: " in
    let _  = print .<im>. in
    {im with pixels = Array.map brighten im.pixels} in
  let res = List.map process ims in
  let _ = print .<res>. in
  Format.printf " <at> ."

let () = some_processing v;;

The list of images, an image itself, and a single pixel were all
printed generically. We did not have to define any custom
printers. Here's the output:

Processing: {title = "im1"; pixels = [|Blue; Rgb 10|]}
pixel: [Blue] -> [Green] 

pixel: [Rgb 10] -> [Rgb 11] 
Processing: {title = "im2"; pixels = [|Green|]}
pixel: [Green] -> [Rgb 10] 
[{title = "im1"; pixels = [|Green; Rgb 11|]};
 {title = "im2"; pixels = [|Rgb 10|]}]

POLYMORPHISM vs. GENERIC

The function print is generic but not polymorphic. For example, if we
define
     let pr x = print .<x>.; x

and invoke the function as "pr [10]", we see the printed output
"<poly>". The function 'pr' has the type 'a->'a -- that is, it
promises to take the value of any type, regardless of its
structure. The function does not even need to know what is the exact
type of its argument, because it is irrelevant. Informally, an OCaml
function of the type ['a-> ...]  corresponds to the Haskell function
[a -> ...]. OTH, an OCaml function of the type [('a,'b) code -> ...]
corresponds to Haskell's [Typeable b => b -> ...]. The latter
enables generic programming.
      

OCaml interface to WordNet

Archive: http://thread.gmane.org/gmane.comp.lang.caml.general/32766/focus=32766

Ramu Ramamurthy announced:
This package contains the OCaml Interface to WordNet.
It enables Ocaml programs to use
the Wordnet dictionary for (english) word forms and
meanings. For more information on WordNet refer
http://wordnet.princeton.edu/

This library directly parses the WordNet dictionary
files, and does not depend on any other libraries.
This library is released under the BSD license and
is available at:

http://ramamurthy.ramu.googlepages.com/ocamlwordnet

The package contains:

    * README.txt 
    * wordnet.mli (Module Interface)
    * wordnet.ml  (Module Implementation)
    * related.ml  (Example Application OCaml WordNet
API)

Example Application:

related.ml contains a toy application of the 
api. Given a word, it finds related words - related
as a synonym or as a "sibling" under the HYPONYM/
HYPERNYM relationship between meanings.

   relatedWords "camel"
   gives

 [(0, "camel"); (0, "hippo"); (0, "hippopotamus");
 (0, "hippopotamus_amphibius"); (0, "llama"); (0,
"musk_hog");
 (0, "peccary"); (0, "river_horse"); (0, "ruminant");
(0, "swine");
 (0, "vicugna_vicugna"); (0, "vicuna")]

   relatedWords "google"
   gives

 [(0, "google"); (0, "google"); (1, "cast_around");
(1, "re-explore");
 (0, "ask_jeeves"); (0, "beat_about"); (0,
"cast_about"); (0, "prospect");
 (0, "yahoo")]
      

recursion/iterator question

Archive: http://thread.gmane.org/gmane.comp.lang.caml.general/32755/focus=32755

Tato Thetza asked:
Given a list, I would like to iterate over all triplets in the list. For
example, in mathematcs, its not uncommon to have expressions such as
"for all i,j,k in set X, do f(i,j,k)"

The only way I can think of is to create a list with all triplets of the
list, so:
  triplets([1,2,3,4]) = [(1,2,3),(1,2,4),(1,3,4),(2,3,4)]
and take this list and map a function f to it.

questions: 
1) what would be the best way to write triplets?
2) is there a cleaner way to iterate over all triplets in a list?
      
David Powers suggested:
The best way would probably be to write a permutation function that 
returns a list of triplets given a list, and then to use List.iter and a 
local function to split out each triplet to work on the component 
parts... something like:

let for_each_trip lst =
    let real_work (a, b, c) =
        (* do some stuff with a b and c in here *)
    in
        List.iter real_work (permute_triples lst)

(loose code - forgive my laziness)

This could be made more general by improving the permute code to take a 
number option and to return triplets of that number  (permute 3 lst).  
In addition you could make the internal function (real_work) be a 
parameter of the for_each... which would reduce all of this to the more 
general

List.iter any_function_I_want (permute 3 lst)

Finally, you might want to consider using lazy evaluation in your 
permute function to avoid calculating every permutation up front.  See 
http://caml.inria.fr/pub/docs/manual-ocaml/libref/Lazy.html for more on 
that.
      
Martin Jambon suggested:
> 1) what would be the best way to write triplets?

You can use list comprehensions.
See http://oandrieu.nerim.net/ocaml/#pa_compr

let triplets l = [+ (x, y, z)
                 | x <- l
                 | y <- l
                 | z <- l
                 | when x < y && y < z ];;

That's not optimal, but it's pretty clear.

> 2) is there a cleaner way to iterate over all triplets in a list?

You can do that, it should perform better:

let rec iter_full f = function
     [] -> ()
   | x :: l -> f x l; iter_full f l

let iter_tail iter f l = iter_full (fun x l -> iter (f x) l) l

let iter_full3 f l = iter_tail (iter_tail iter_full) f l

let iter3 f l = iter_full3 (fun x y z _ -> f x y z) l
      
Jon Harrop suggested:
> 1) what would be the best way to write triplets?

As 3-tuples, as you have done.

> 2) is there a cleaner way to iterate over all triplets in a list?

I think you mean _tabulate_ all triplets _from_ a list. You can write a 
function to tabulate all pairs like this:

# let rec f2 = function
    [] -> []
  | a::t -> List.map (fun b -> a, b) t  <at>  f2 t;;
val f2 : 'a list -> ('a * 'a) list = <fun>

and then another to tabulate all triplets like this:

# let rec f3 = function
    [] -> []
  | a::t -> List.map (fun (b, c) -> a, b, c) (f2 t)  <at>  f3 t;;
val f3 : 'a list -> ('a * 'a * 'a) list = <fun>

On the example you gave:

# f3 [1;2;3;4];;
- : (int * int * int) list = [(1, 2, 3); (1, 2, 4); (1, 3, 4); (2, 3, 4)]
      
Christian Stork then added:
Just in case you didn't know, you're looking for an enumeration of all
"3-sets" or "combinations" out of the set X.  See for example
http://mathworld.wolfram.com/Combination.html .

> > The only way I can think of is to create a list with all triplets of the
> > list, so:
> >   triplets([1,2,3,4]) = [(1,2,3),(1,2,4),(1,3,4),(2,3,4)]
> > and take this list and map a function f to it.

> > questions:
> > 1) what would be the best way to write triplets?

> As 3-tuples, as you have done.

Or, if you choose to represent triplets as lists of three elements, you can
generalize Jon's solution to

  let rec combs = function
      | (0, _) -> [[]]
      | (n, es) when n > List.length es -> []
      | (n, e::es) -> List.map (fun l -> e::l) (combs (n-1, es))  <at>  combs (n, es)
  let triplets es = combs (3, es)

Question to the rest of the list:  The ocaml compiler complains with 
  ...
  Warning P: this pattern-matching is not exhaustive.
  Here is an example of a value that is not matched:
  (1, [])
  (However, some guarded clause may match this value.)
  ...

Am I right to assume there's no way to get rid of this warning short of
disabling P-warnings on the command line?  (I can't list all the lacking
patterns since they depend on n, right?)
      
Jonathan Roewen answered:
Personally, if you know it can never be reached, then an assertion is
probably better.

| otherwise -> assert false (* I prefer using a name like otherwise
rather than _ for pure readability value *)
      
Li-Thiao-Té Sébastien replied to the original message and Nils Gesbert added:
> I suggest turning the list into an array, then using for-loops instead 
> of trying to explicitly generate the list of all possible triplets. If 
> you need to accumulate the results, you can use a list ref. This amounts 
> to implementing a set using an array instead of a list; unfortunately it 
> is not functional :(
> 
> let iterate f l =
>    let t = Array.of_list l in
>    let n = Array.length t in
>    let results = ref [] in
>    for i = 0 to n-1 do
>      for j = 0 to n-1 do
>        for k = 0 to n-1 do
>          results := f (t.(i),t.(j),t.(k)) :: results
> done done done
> ;;

A functional version of this could be (assuming f is curryed, and without keeping results) :
let iter3 f l =
   let rec it2 iter g = function
      h::t -> iter (g h) l; it2 iter g t
    | _ -> ()
   in it2 (it2 List.iter) f l

But I think the goal was to iterate over triplets (a,b,c) with a < b < c, not over all triplets. If I am not
mistaken, it suffices to replace the l on line 3 by t to get this behaviour.
      
Xavier Leroy also replied to the original message:
Folds are more general than maps and tend to compose better.
Consider:

let list_fold_right_3 f l1 l2 l3 =
  List.fold_right
    (fun x1 -> List.fold_right (fun x2 -> List.fold_right (f x1 x2) l3) l2)
    l1

Examples:

# list_fold_right_3 (fun x y z a -> (x,y,z)::a) [1;2] [3;4] [5;6] [];;
- : (int * int * int) list =
[(1, 3, 5); (1, 3, 6); (1, 4, 5); (1, 4, 6); (2, 3, 5); (2, 3, 6); (2,
4, 5);
 (2, 4, 6)]
# list_fold_right_3 (fun x y z a -> (x+y+z)::a) [1;2] [3;4] [5;6] [];;
- : int list = [9; 10; 10; 11; 10; 11; 11; 12]
# list_fold_right_3 (fun x y z a -> x*y*z + a) [1;2] [3;4] [5;6] 0;;
- : int = 231
      

Using folding to read the cwn in vim 6+

Here is a quick trick to help you read this CWN if you are viewing it using vim (version 6 or greater).

:set foldmethod=expr
:set foldexpr=getline(v:lnum)=~'^=\\{78}$'?'&lt;1':1
zM

If you know of a better way, please let me know.


Old cwn

If you happen to miss a CWN, you can send me a message and I'll mail it to you, or go take a look at the archive or the RSS feed of the archives.

If you also wish to receive it every week by mail, you may subscribe online.


Alan Schmitt