Comprehension for OCaml

Comprehension for OCaml is a small syntax extension for OCaml 3.10, developed using Camlp4. The latest release is version 0.1.1, released December 18, 2007, which you may find here.

This extension adds or improves support for list comprehension, array comprehension, stream comprehension, lazy list comprehension and string comprehension inside OCaml. It may be used with either the revised syntax or the original syntax.

Comments, suggestions and bug reports are welcome.

Last Updates

12/18/2007

Fixed error in the documentation.

 

Syntax extensions

Examples in the original syntax may be found here. Examples in the revised syntax may be found here.

List comprehension

As in standard syntax, lists may be written

[] (*The empty list*)
[1] (*The list containing 1*)
[1;2] (*The list containing 1 and 2*)

plus, in the original syntax

1 :: [2;3;4](*The list containing 1, 2, 3 and 4*)

or, in the revised syntax

[1;2::[3;4]](*The list containing 1, 2, 3 and 4*)

With this extension, list ranges may now be written

[1 .. 20]
let a = 1 and b = 20 in [a .. b]
[0;1;2..18;19;20]

All these expressions produce the list of integers between 1 and 20. These lists are computed at run-time.

  • This feature requires module MoreList, included in this distribution as source file moreList.ml .

As in the revised syntax, list comprehension loops may be written

[ i+1 | i <- [1;2;3;4;5] ] (*The list [2;3;4;5;6] *)
[ i+1 | i <- [1;2;3;4;5] ; i mod 2 = 0] (*The list [3;5] *)
[(i,j)| i <- [1;2] ; j <- [3;4]] (*The list [(1,3);(1,4);(2,3);(2,4)] *)

In addition, list comprehension loops may now be read from other data structures

[ i | (MoreString) i <- "aeiou" ] (*The list ['a';'e';'i';'o';'u'] *)

 

  • This feature works with any module containing functions map, filter, flatten, map_filter and to_list with types similar to those of the corresponding functions in module MoreArray. A few modules are included with the necessary functions for lists, arrays, lazy lists strings and streams.

Array comprehension

As in the revised syntax, arrays may be written

[||] (*The empty array*)
[|1|] (*The array containing 1*)
[|1;2|] (*The array containing 1 and 2*)

With this extension, array ranges may now be written

[|1 .. 20|]
[|0;1;2..18;19;20|]
let a = 1 and b = 20 in [|a .. b|]
[|(0+1)..19;20|]

All these expressions produce the array of integers between 1 and 20. The first and second cases
are computed at compile-time, without array concatenations, while the third and fourth cases and
anything more complex need run-time computation. The fourth case additionally requires run-time
concatenations.

  • This feature requires module MoreArray, included in this distribution as source file moreList.ml .

As for lists, array comprehension loops may be written

[| i+1 | i <- [|1;2;3;4;5|] |] (*The array [|2;3;4;5;6|] *)
[| i+1 | i <- [|1;2;3;4;5|] ; i mod 2 = 0|] (*The array [|3;5|] *)
[|(i,j)| i <- [|1;2|] ; j <- [|3;4|] |] (*The array [|(1,3);(1,4);(2,3);(2,4)|] *)

In addition, array comprehension loops may now be read from other data structures
(”cross-comprehension”)

[| i | (MoreString) i <- "aeiou" |] (*The array [|'a';'e';'i';'o';'u'|] *)

 

  • This feature works with any module containing functions map, filter, flatten, map_filter and to_array with types similar to those of the corresponding functions in module MoreArray. A few modules are included with the necessary functions for lists, arrays, lazy lists strings and streams.

Stream comprehension

If you’re using the original syntax, you may already write

[< >] (*The empty stream*)
[< '1>] (*The stream containing 1*)
[< '1;'2 >] (*The stream containing 1 and 2*)
[< '1; '2; [< '3; '4>] >] (*The stream containing 1,2,3 and 4*)

With this extension, stream ranges may now be written

[< 1 .. 20 >]
[< `0; `1; 2..18; `19; `20 >]
let a = 1 and b = 20 in [< `a .. `b >]
[< (0+1)..19; `20 >]

If you’re using the revised syntax, you may still write

[: :] (*The empty stream*)
[: `1:] (*The stream containing 1*)
[: `1;`2 :] (*The stream containing 1 and 2*)
[: `1; `2; [: `3; `4:] :] (*The stream containing 1,2,3 and 4*)

and now

[: 1 .. 20 :]
[:`0;`1;2..18;`19;`20 :]
let a = 1 and b = 20 in [: `a .. `b :]
[: (0+1)..19;`20 :]

These expressions produce the stream of integers between 1 and 20. Concatenations, when
needed, are performed lazily, at run-time.

  • This feature requires module MoreStream, included in this distribution as source file moreList.ml .
  • This feature requires module Sdflow, included in this distribution as source file sdflow.ml .

This extension also adds stream comprehension loops may be written, either in the original syntax

[< i+1 | i <- [< '1;'2;'3;'4;'5 >] >] (*The stream [<'2; '3; '4; '5; '6>] *)
[< i+1 | i <- [< '1;'2;'3;'4;'5 >] ; i mod 2 = 0 >] (*The stream [<'3; '5>] *)
[<(i,j)| i <- [< '1;'2 >] ; j <- [< '3;'4 >] >] (*The stream [<'(1,3); '(1,4); '(2,3); '(2,4)>] *)

or,in the revised syntax

[: i+1 | i <- [:`1;`2;`3;`4;`5:] :] (*The stream [:`2;`3;`4;`5;`6:] *)
[: i+1 | i <- [:`1;`2;`3;`4;`5:] ; i mod 2 = 0:] (*The stream [:`3;`5:] *)
[:(i,j)| i <- [:`1;`2:] ; j <- [:`3;`4:] :] (*The stream [:`(1,3);`(1,4);`(2,3);`(2,4):] *)

In addition, stream comprehension loops may be read from other data structures
(”cross-comprehension”)

[< i | (MoreString) i <- "aeiou" >] (*The stream [<'"a";'"e";'"i";'"o";'"u">] *)
[: i | (MoreString) i <- "aeiou" :] (*The stream [:`"a";`"e";`"i";`"o";`"u":] *)

 

  • This feature works with any module containing functions map, filter, flatten, map_filter and to_stream with types similar to those of the corresponding functions in module MoreArray. A few modules are included with the necessary functions for lists, arrays, lazy lists strings and streams.
  • If you use this feature, do take a look at Sdflow for additional operators, such as parallel composition, etc.

Lazy List comprehension

Lazy Lists are defined in module LList
Lazy Lists may be written either using LList.Nil and LList.Cons or using
the following syntax


[^ ^] (*The empty lazy list*)
[^ 1 ^] (*The lazy list containing 1*)
[^ 1;2 ^] (*The lazy list containing 1 and 2*)

Plus, if you’re using the original syntax


1 ^:^ [^ 2;3;4 ^]

or, if you’re using the revised syntax


[^ 1 :: [^ 2;3;4 ^] ^] .

In addition, lazy list ranges may be written, in either syntax

[^ 1 .. 20 ^]
[^ 0;1;2..18;19;20 ^]
let a = 1 and b = 20 in [^ a .. b ^]
[^ (0+1)..19;20 ^]

All these expressions produce the lazy list of integers between 1 and 20. These lazy lists are always
computed at run-time, lazily.

  • This feature requires module MoreLazy List, included in this distribution as source file moreList.ml .

As for lists, lazy list comprehension loops may be written

[^ i+1 | i <- [^ 1;2;3;4;5 ^] ^] (*The lazy list [^ 2;3;4;5;6 ^] *)
[^ i+1 | i <- [^ 1;2;3;4;5 ^] ; i mod 2 = 0 ^] (*The lazy list [^ 3;5 ^] *)
[^ (i,j)| i <- [^ 1;2 ^] ; j <- [^ 3;4 ^] ^] (*The lazy list [^ (1,3);(1,4);(2,3);(2,4) ^] *)

In addition, lazy list comprehension loops may now be read from other data structures
(”cross-comprehension”)

[^ i | (MoreString) i <- "aeiou" ^] (*The lazy list [^ 'a';'e';'i';'o';'u' ^] *)

 

  • This feature works with any module containing functions map, filter, flatten, map_filter and to_lazylist with types similar to those of the corresponding functions in module MoreArray. A few modules are included with the necessary functions for lists, arrays, lazy lists strings and streams.

Some code is inlined from Camlp4 3.10’s source code by Daniel de Rauglaudre and Nicolas Pouillard.
You may find Camlp4 at http://www.ocaml.org .

Loops

This is an expansion of Likai Liu’s Camlp4 3.10/Foreach Tutorial, available as part of the OCaml Tutorial.

OCaml allows writing

for i = 0 to n do
(*bla*)
done

With the Loop syntax extensions, one may write

for each i in MoreStream [: 1 .. n :] do
print_int i
done (*Maps to MoreStream.iter (fun i -> print_int i) [: 1 .. n :] *)


for each i c in Array.iteri [| 'a'; 'b'; 'c'; 'd' |] do
Printf.printf “%d -> %c\n” i c
done (*Maps to Array.iteri (fun i c -> Printf.printf “%d -> %c\n” i c) [| 'a'; 'b'; 'c'; 'd' |] *)


for each (x,y) in List [| (1,2); (3,4); (5,6) |] do
Printf.printf “(%d,%d)\n” x y
done (*Maps to List.iter (fun (x,y) -> Printf.printf “(%d,%d)\n” x y) [| (1,2); (3,4); (5,6) |] *)

More generally, there are two syntaxes:


for each pattern_1 pattern2 … in Module value do
some_body
done (*Maps to Module.iter (fun pattern_1 pattern_2 … -> some_body) value *)

or

for each pattern_1 pattern2 … in function_identifier value do
some_body
done (*Maps to function_identifier (fun pattern_1 pattern_2 … -> some_body) value *)

Modules

Documentation of the modules may be found here.

Flows

This packages contains a verbatim inclusion of Zheng Li’s SDFlow 0.01, included here as

  1. it’s not a very common library (it’s not available with GODI, in particular)
  2. it’s a dependency of MoreStream

MoreArray, MoreStream, MoreString, MoreList, LList

Various utilities for manipulation of arrays, streams, strings, lists and lazy lists. These utilities are necessary for the corresponding comprehensions. Documentation

Un commentaire »

  1. Comprehension for OCaml « Il y a du thé renversé au bord de la table a dit,

    décembre 18, 2007 à 12:26

    [...] Publié dans En français, Enseignement, In English, Informatique, Recherche tagged arrays, camlp4, chaînes de caractères, data structures, flux, haskell, laziness, lazy, list comprehension, listes, listes paresseuses, lists, ocaml, programmation, programming, streams, strings, structures de données, sucre syntaxique, syntaxe, tableaux à 12:26 par yoric I have just released a first version of a syntax extension for OCaml, improving comprehension for lists, strings, streams, lazy lists and arrays. More informations here. [...]

Apporter un Commentaire