Commits

Vadim Shender committed 9eac3d4

Parallel list comprehension added

Comments (0)

Files changed (13)

+version 0.2:
+  * Parallel list comprehension
+  * Examples and tests for parallel list comprehension
+  * Code cleaning
+
 version 0.1:
-  * First public release
-
+  First public release
   * syntax extension with support for
       - lazy list construction and generation
       - lazy list comprehension
+      - parallel lazy list comprehension
       - lazy list pattern matching
 
 Usage examples for original syntax see in examples/llistcons_orig.ml,

examples/llistcomp_orig.ml

                          let j = fact i ]
 in to_list l
 (* - : (int * int) list = [(1, 1); (2, 2); (3, 6); (4, 24); (5, 120)] *)
+
+
+
+(* Parallel lazy list comprehension. *)
+
+(* http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#parallel-list-comprehensions *)
+
+
+let l = [% x, y | x <- [% 1; 3 .. 9 ] | y <- [% 2; 4 .. 10 ] ]
+in to_list l
+(* - : (int * int) list = [(1, 2); (3, 4); (5, 6); (7, 8); (9, 10)] *)
+
+let l = [% x, y | x <- [% 1; 3 .. ] | y <- [% 2; 4 .. 10 ] ]
+in to_list l
+(* - : (int * int) list = [(1, 2); (3, 4); (5, 6); (7, 8); (9, 10)] *)

examples/llistcomp_rev.ml

                            let j = fact i ]
 in to_list l ;
 (* - : list (int * int) = [(1, 1); (2, 2); (3, 6); (4, 24); (5, 120)] *)
+
+
+
+(* Parallel lazy list comprehension. *)
+
+(* http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#parallel-list-comprehensions *)
+
+
+let l = [% (x, y) | x <- [% 1; 3 .. 9 ] | y <- [% 2; 4 .. 10 ] ]
+in to_list l ;
+(* - : list (int * int) = [(1, 2); (3, 4); (5, 6); (7, 8); (9, 10)] *)
+
+let l = [% (x, y) | x <- [% 1; 3 .. ] | y <- [% 2; 4 .. 10 ] ]
+in to_list l ;
+(* - : list (int * int) = [(1, 2); (3, 4); (5, 6); (7, 8); (9, 10)] *)
 (* Lazy list implementation
  *
  * Author: Vadim Shender
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
 and  'a t = 'a node_t lazy_t
 
 
-external follow_forward : Obj.t -> 'a = "caml_lazy_follow_forward"
-external make_forward : 'a -> 'a lazy_t = "caml_lazy_make_forward"
-
-
-let lazy_apply f l =
-  lazy (f (Lazy.force l))
-
-
 let fold_left ?limit f init lst =
   let rec fold_left_inf accu rest =
     match Lazy.force rest with
 
 
 let rec append lst1 lst2 =
-  let append' = function
-      Nil         -> Lazy.force lst2
-    | Cons (h, t) -> Cons (h, append t lst2)
-  in lazy_apply append' lst1
+  lazy ( match Lazy.force lst1 with
+           Nil         -> Lazy.force lst2
+         | Cons (h, t) -> Cons (h, append t lst2) )
 
-let concat lstlst =
-  let rec concat_aux lst1 llrest =
-    let concat' llrest = function
-        Nil         ->
-          ( match Lazy.force llrest with
-              Nil                    -> Nil
-            | Cons (lstnext, llrest) -> Lazy.force (concat_aux lstnext llrest) )
-      | Cons (h, t) -> Cons (h, concat_aux t llrest)
-    in lazy_apply (concat' llrest) lst1
-  in
-  match Lazy.force lstlst with
-    Nil         -> empty
-  | Cons (h, t) -> concat_aux h t
+let rec concat lstlst =
+  lazy ( match Lazy.force lstlst with
+           Nil         -> Nil
+         | Cons (h, t) -> Lazy.force (append h (concat t) ) )
 
 let flatten = concat
 
               else           invalid_arg "Lazy_list.iteri"
 
 let rec map f lst =
-  let map' = function
-      Nil         -> Nil
-    | Cons (h, t) -> Cons (f h, map f t)
-  in lazy_apply map' lst
+  lazy ( match Lazy.force lst with
+           Nil         -> Nil
+         | Cons (h, t) -> Cons (f h, map f t) )
 
 let rec mapi ?(starti=0) f lst =
-  let mapi' i = function
-      Nil         -> Nil
-    | Cons (h, t) -> Cons (f i h, mapi ~starti:(i + 1) f t)
-  in lazy_apply (mapi' starti) lst
+  lazy ( match Lazy.force lst with
+           Nil         -> Nil
+         | Cons (h, t) -> Cons (f starti h, mapi ~starti:(starti + 1) f t) )
 
 
 let iter2 ?limit f lst1 lst2 =
     | n ->
         match Lazy.force lst1, Lazy.force lst2 with
           Nil, Nil                     -> ()
-        | Cons (h1, t1), Cons (h2, t2) -> let () = f h1 h2 in iter2_fin t1 t2 (n - 1)
+        | Cons (h1, t1), Cons (h2, t2) ->
+          let () = f h1 h2 in iter2_fin t1 t2 (n - 1)
         | _                            -> invalid_arg "Lazy_list.iter2"
   in
   match limit with
     None   -> iter2_inf lst1 lst2
-  | Some n -> if n >= 0 then iter2_fin lst1 lst2 n else invalid_arg "Lazy_list.iter2"
+  | Some n -> if n >= 0 then iter2_fin lst1 lst2 n
+              else           invalid_arg "Lazy_list.iter2"
 
 let iteri2 ?limit ?(starti=0) f lst1 lst2 =
   let rec iteri2_inf lst1 lst2 i =
     | n ->
         match Lazy.force lst1, Lazy.force lst2 with
           Nil, Nil                     -> ()
-        | Cons (h1, t1), Cons (h2, t2) -> let () = f i h1 h2 in iteri2_fin t1 t2 (i + 1) (n - 1)
+        | Cons (h1, t1), Cons (h2, t2) ->
+          let () = f i h1 h2 in iteri2_fin t1 t2 (i + 1) (n - 1)
         | _                            -> invalid_arg "Lazy_list.iteri2"
   in
   match limit with
               else           invalid_arg "Lazy_list.iteri2"
 
 let rec map2 f lst1 lst2 =
-  let map2' lst1_unwrapped =
-    match lst1_unwrapped, Lazy.force lst2 with
-      Nil, Nil                     -> Nil
-    | Cons (h1, t1), Cons (h2, t2) -> Cons (f h1 h2, map2 f t1 t2)
-    | _                            -> invalid_arg "Lazy_list.map2"
-  in lazy_apply map2' lst1
+  lazy ( match Lazy.force lst1, Lazy.force lst2 with
+           Nil, Nil                     -> Nil
+         | Cons (h1, t1), Cons (h2, t2) -> Cons (f h1 h2, map2 f t1 t2)
+         | _                            -> invalid_arg "Lazy_list.map2" )
 
 let rec mapi2 ?(starti=0) f lst1 lst2 =
-  let mapi2' i lst1_unwrapped =
-    match lst1_unwrapped, Lazy.force lst2 with
-      Nil, Nil                     -> Nil
-    | Cons (h1, t1), Cons (h2, t2) -> Cons (f i h1 h2, mapi2 ~starti:(i + 1) f t1 t2)
-    | _                            -> invalid_arg "Lazy_list.mapi2"
-  in lazy_apply (mapi2' starti) lst1
+  lazy ( match Lazy.force lst1, Lazy.force lst2 with
+           Nil, Nil                     -> Nil
+         | Cons (h1, t1), Cons (h2, t2) ->
+           Cons (f starti h1 h2, mapi2 ~starti:(starti + 1) f t1 t2)
+         | _                            -> invalid_arg "Lazy_list.mapi2" )
 
 let fold_left2 ?limit f init lst1 lst2 =
   let rec fold_left2_inf accu lst1 lst2 =
     | n ->
         match Lazy.force lst1, Lazy.force lst2 with
           Nil, Nil                     -> accu
-        | Cons (h1, t1), Cons (h2, t2) -> fold_left2_fin (f accu h1 h2) t1 t2 (n - 1)
+        | Cons (h1, t1), Cons (h2, t2) ->
+          fold_left2_fin (f accu h1 h2) t1 t2 (n - 1)
         | _                            -> invalid_arg "Lazy_list.fold_left2"
   in
   match limit with
     | n ->
         match Lazy.force lst1, Lazy.force lst2 with
           Nil, Nil                     -> init
-        | Cons (h1, t1), Cons (h2, t2) -> f h1 h2 (fold_right2_fin t1 t2 (n - 1))
+        | Cons (h1, t1), Cons (h2, t2) ->
+          f h1 h2 (fold_right2_fin t1 t2 (n - 1))
         | _                            -> invalid_arg "Lazy_list.fold_right2"
   in
   match limit with
   in
   match limit with
     None   -> for_all_inf lst
-  | Some n -> if n >= 0 then for_all_fin lst n else invalid_arg "Lazy_list.for_all"
+  | Some n -> if n >= 0 then for_all_fin lst n
+              else           invalid_arg "Lazy_list.for_all"
 
 let exists ?limit p lst =
   let rec exists_inf lst =
   in
   match limit with
     None   -> exists_inf lst
-  | Some n -> if n >= 0 then exists_fin lst n else invalid_arg "Lazy_list.exists"
+  | Some n -> if n >= 0 then exists_fin lst n
+              else           invalid_arg "Lazy_list.exists"
 
 let for_all2 ?limit p lst1 lst2 =
   let rec for_all2_inf lst1 lst2 =
               else           invalid_arg "Lazy_list.findi"
 
 let rec find_all p lst =
-  let rec find_all' = function
-      Nil                  -> Nil
-    | Cons (h, t) when p h -> Cons (h, find_all p t)
-    | Cons (_, t)          -> find_all' (Lazy.force t)
-  in lazy_apply find_all' lst
+  lazy ( match Lazy.force lst with
+           Nil                  -> Nil
+         | Cons (h, t) when p h -> Cons (h, find_all p t)
+         | Cons (_, t)          -> Lazy.force (find_all p t) )
 
 let filter = find_all
 
 
 let split lst =
   let rec fst lst =
-    let fst' = function 
-        Nil              -> Nil
-      | Cons ((h, _), t) -> Cons (h, fst t)
-    in lazy_apply fst' lst
+    lazy ( match Lazy.force lst with
+             Nil              -> Nil
+           | Cons ((h, _), t) -> Cons (h, fst t) )
   and     snd lst =
-    let snd' = function
-        Nil              -> Nil
-      | Cons ((_, h), t) -> Cons (h, snd t)
-    in lazy_apply snd' lst
+    lazy ( match Lazy.force lst with
+             Nil              -> Nil
+           | Cons ((_, h), t) -> Cons (h, snd t) )
   in fst lst, snd lst
 
 let rec combine lst1 lst2 =
-  let combine' lst1_unwrapped =
-    match lst1_unwrapped, Lazy.force lst2 with
-      Nil, Nil                     -> Nil
-    | Cons (h1, t1), Cons (h2, t2) -> Cons ((h1, h2), combine t1 t2)
-    | _                            -> invalid_arg "Lazy_list.combine"
-  in lazy_apply combine' lst1
-            
-        
+  lazy ( match Lazy.force lst1, Lazy.force lst2 with
+           Nil, Nil                     -> Nil
+         | Cons (h1, t1), Cons (h2, t2) -> Cons ((h1, h2), combine t1 t2)
+         | _                            -> invalid_arg "Lazy_list.combine" )
+
+
 let split_nth n lst =
   let rec take n lst =
-    let take' = function
-        Nil         -> invalid_arg "Lazy_list.split_nth"
-      | Cons (h, t) -> Cons (h, take (n - 1) t)
-    in if n = 0 then empty else lazy_apply take' lst
+    if n = 0 then empty else
+      lazy ( match Lazy.force lst with
+               Nil         -> invalid_arg "Lazy_list.split_nth"
+             | Cons (h, t) -> Cons (h, take (n - 1) t) )
   and     drop n lst =
-    let drop' = function
-        Nil         -> invalid_arg "Lazy_list.split_nth"
-      | Cons (_, t) -> Lazy.force (drop (n - 1) t)
-    in if n = 0 then lst else lazy_apply drop' lst
+    if n = 0 then lst else
+      lazy ( match Lazy.force lst with
+               Nil         -> invalid_arg "Lazy_list.split_nth"
+             | Cons (_, t) -> Lazy.force (drop (n - 1) t) )
   in
   if n >= 0 then take n lst, drop n lst else invalid_arg "Lazy_list.split_nth"
 
 let rec take n lst =
-  let take' = function
-      Nil         -> Nil
-    | Cons (h, t) -> Cons (h, take (n - 1) t)
-  in if n > 0 then lazy_apply take' lst else empty
+  if n < 1 then empty else
+    lazy ( match Lazy.force lst with
+             Nil         -> Nil
+           | Cons (h, t) -> Cons (h, take (n - 1) t) )
 
 let rec drop n lst =
-  let drop' = function
-      Nil         -> Nil
-    | Cons (_, t) -> Lazy.force (drop (n - 1) t)
-  in if n > 0 then lazy_apply drop' lst else lst
+  if n < 1 then lst else
+    lazy ( match Lazy.force lst with
+             Nil         -> Nil
+           | Cons (_, t) -> Lazy.force (drop (n - 1) t) )
 
 let rec takewhile p lst =
-  let takewhile' = function
-      Nil         -> Nil
-    | Cons (h, t) -> if p h then Cons (h, takewhile p t) else Nil
-  in lazy_apply takewhile' lst
+  lazy ( match Lazy.force lst with
+           Nil         -> Nil
+         | Cons (h, t) -> if p h then Cons (h, takewhile p t) else Nil )
 
 let rec dropwhile p lst =
-  let dropwhile' = function
-      Nil              -> Nil
-    | Cons (h, t) as c -> if p h then Lazy.force (dropwhile p t) else c
-  in lazy_apply dropwhile' lst
+  lazy ( match Lazy.force lst with
+           Nil              -> Nil
+         | Cons (h, t) as c -> if p h then Lazy.force (dropwhile p t) else c )
 
 
-let rec of_list lst = 
+let rec of_list lst =
   lazy ( match lst with
            []     -> Nil
          | h :: t -> Cons (h, of_list t) )
 (* Lazy list interface
  *
  * Author: Vadim Shender
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
 (** The empty lazy list. *)
 
 val cons : 'a -> 'a t -> 'a t
-(** [Lazy_list.cons hd tl] constructs new lazy list from [hd] and lazy list [tl]. *)
+(** [Lazy_list.cons hd tl] constructs new lazy list from [hd] and lazy list
+    [tl]. *)
 
 val init : ?limit:int -> ?starti:int -> (int -> 'a) -> 'a t
 (** [Lazy_list.init f] constructs new lazy list with element number [i]
     given then counting is only bound by the first [limit] memebers of the lazy
     list [l] (it may be useful for assuring that list has at least [limit]
     elements: [length ~limit:limit l = limit]. Without given [limit] it'll loop
-    infinitely on an infinite lazy list.
-
- It'll loop
     infinitely on an infinite lazy list. *)
 
 
     [Invalid_argument "Lazy_list.iter2"] if the two lists have different lengths
     or [limit] is negative. *)
 
-val iteri2 : ?limit:int -> ?starti:int -> (int -> 'a -> 'b -> unit) -> 'a t -> 'b t -> unit
+val iteri2 : ?limit:int -> ?starti:int ->
+             (int -> 'a -> 'b -> unit) -> 'a t -> 'b t -> unit
 (** Same as [Lazy_list.iter2], but function [f] is applied to serial number of a
     pair of lazy list elements (starting from 0 by default) together with those
     elements itself. [Lazy_list.iteri2 f [% a1; a2; ... ] [% b1; b2; ... ]] is
     [Invalid_argument "Lazy_list.map2"] if the two lists have different
     lengths. *)
 
-val fold_left2 : ?limit:int -> ('a -> 'b -> 'c -> 'a) -> 'a -> 'b t -> 'c t -> 'a
+val fold_left2 : ?limit:int ->
+                 ('a -> 'b -> 'c -> 'a) -> 'a -> 'b t -> 'c t -> 'a
 (** [Lazy_list.fold_left2 f a [% b1; ...; bn ] [% c1; ...; cn ]] is
     [f (... (f (f a b1 c1) b2 c2) ...) bn cn]. If [limit] is given then folding
     is only bound by the first [limit] members of the lazy lists. Without
 
 
 val mem : ?limit:int -> 'a -> 'a t -> bool
-(** [Lazy_list.mem a l] is true if and only if [a] is equal to an element of l. *)
+(** [Lazy_list.mem a l] is true if and only if [a] is equal to an element of
+    l. *)
 
 val memq : ?limit:int -> 'a -> 'a t -> bool
 (** Same as [Lazy_list.mem], but uses physical equality instead of structural
 (* Lazy list comprehension syntax extension
  *
  * Author: Vadim Shender
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
 
 module S = Set.Make (String)
 
+
 let vars_of_patt =
   let fold_vars_of_patt =
     object (self)
   | `Gen (p, l) :: items ->
       ( match compr_branch_aux _loc e items with
           `C_gen e'             -> `C_gen (concat _loc (map _loc p e' l))
-        | `C_guard (b, e')      -> `C_gen (concat _loc (map _loc p e' (filter _loc p b l)))
+        | `C_guard (b, e')      -> `C_gen (concat _loc (map _loc p e'
+                                                          (filter _loc p b l)))
         | `C_expr e'            -> `C_gen (map _loc p e' l)
         | `C_guard_expr (b, e') -> `C_gen (map _loc p e' (filter _loc p b l)) )
   | `Guard b :: items ->
             let fb = does_binding_bind_free_vars_of_expr bi b
             and fe = does_binding_bind_free_vars_of_expr bi e' in
             `C_guard_expr ( (if fb then let_binding _loc rf bi b else b),
-                            (if fe || not fb then let_binding _loc rf bi e' else e') ) )
+                            (if fe || not fb then let_binding _loc rf bi e'
+                             else                 e') ) )
   | [] -> `C_expr e
   | _ -> raise Stream.Failure
 
       (* It surely will cause the error "Unbound value .." *)
       <:expr< if $b$ then $e$ else Lazy_list.empty >>
 
+
+let vars_of_compr_branch =
+  let rec iter accu = function
+      `Gen (p, _) :: rest  ->
+        iter (S.fold (fun n ac -> n :: ac) (vars_of_patt p) accu) rest
+    | `Guard _ :: rest     ->
+        iter accu rest
+    | `Let (_, bi) :: rest ->
+        iter
+          (S.fold (fun n ac -> n :: ac) (binding_vars_of_binding bi) accu) rest
+    | []                   -> accu
+  in iter []
+
+
+let rec interval a b =
+  if a > b then [] else a :: interval (a + 1) b
+
+let exprlist_of_lidlist _loc = List.map (fun l -> <:expr< $lid:l$>>)
+
+let pattlist_of_lidlist _loc = List.map (fun l -> <:patt< $lid:l$>>)
+
+let pa_tup_or_single _loc l =
+  if List.length l > 1 then <:patt< $tup:Ast.paCom_of_list l$ >>
+  else                      <:patt< $List.hd l$ >>
+
+let ex_tup_or_single _loc l =
+  if List.length l > 1 then <:expr< $tup:Ast.exCom_of_list l$ >>
+  else                      <:expr< $List.hd l$ >>
+
+let mkapp _loc f l =
+  let f = <:expr< $lid:f$ >> in
+  List.fold_left (fun f x -> <:expr< $f$ $x$ >>) f l
+
+let zipfunc _loc compr_branches =
+  let n = List.length compr_branches in
+  let zipfunc = "llistcomp_zip_" ^ string_of_int n in
+  let varlist prefix =
+    List.map (fun i -> prefix ^ string_of_int i) (interval 0 (n - 1)) in
+  let pl = varlist "llistcomp_zip_param_"
+  and hl = varlist "llistcomp_zip_hd_"
+  and tl = varlist "llistcomp_zip_tl_" in
+  let base_case =
+    let patt =
+      <:patt< $pa_tup_or_single _loc
+                  ( List.map2
+                      (fun h t -> <:patt< Lazy_list.Cons $lid:h$ $lid:t$ >>)
+                      hl tl )$ >>
+    and action =
+      <:expr<
+        Lazy_list.Cons
+          $ex_tup_or_single _loc (exprlist_of_lidlist _loc hl)$
+          $mkapp _loc zipfunc (exprlist_of_lidlist _loc tl)$ >>
+    in <:match_case< $patt$ -> $action$ >>
+  and rest_cases =
+    [ <:match_case< _ -> Lazy_list.Nil >> ]
+  and expr =
+    <:expr< $ex_tup_or_single _loc
+              (List.map (fun p -> <:expr< Lazy.force $lid:p$ >>) pl)$ >>
+  in
+  let mtch =
+    <:expr< match $expr$ with [ $Ast.mcOr_of_list (base_case :: rest_cases)$ ] >>
+  in
+  let fun_binding =
+    List.fold_right
+      (fun p expr -> <:expr< fun $lid:p$ -> $expr$ >>)
+      pl <:expr< lazy $mtch$ >>
+  in <:expr< let rec $lid:zipfunc$ = $fun_binding$
+             in $mkapp _loc zipfunc compr_branches$ >>
+
+let compr_branches _loc e branches =
+  let vars = List.map vars_of_compr_branch branches in
+  let branches =
+    List.map2
+      ( fun bv b ->
+          compr_branch _loc <:expr< $ex_tup_or_single _loc bv$ >> b )
+      (List.map (exprlist_of_lidlist _loc) vars)
+      branches
+  in
+  map
+    _loc
+    <:patt< $pa_tup_or_single _loc
+               ( List.map
+                   ( fun bv ->
+                       <:patt< $pa_tup_or_single _loc
+                                 (pattlist_of_lidlist _loc bv)$ >> )
+                   vars )$ >>
+    e
+    (zipfunc _loc branches)
+
+
 let rec comprehension _loc e branches =
-  compr_branch _loc e (List.hd branches)  (* parallel list comprehension coming soon... *)
+  if List.length branches < 2 then
+    compr_branch _loc e (List.hd branches)
+  else
+    compr_branches _loc e branches
 
 
 (* new parser for infixop3 grammar entry, which releases "%:" operator *)
   with Not_found ->
     false
 
-let () = Gram.Entry.clear str_item
-
 
 (* syntax for cons operator *)
 
           `Gen (p, e)
       | test_patt_let_without_in;
         "let"; rf = opt_rec; bl = LIST1 item_let_binding SEP "and" ->
-          `Let ( rf, List.fold_left
-                       (fun bi bl -> <:binding< $bi$ and $bl$ >>)
-                       (List.hd bl) (List.tl bl) )
+          `Let (rf, Ast.biAnd_of_list bl)
       | e = expr LEVEL "top" ->
           `Guard e ] ] ;
 
   EXTEND Gram
     GLOBAL: patt ;
 
-    patt: LEVEL "simple" 
+    patt: LEVEL "simple"
       [ [ "[%"; "]" ->
             <:patt< $uid:"lazy_nil"$ >>
         | "[%"; mk_list = sem_patt_for_conses; "::"; last = patt; "]" ->
       [ "%:" RIGHTA
         [ p1 = patt; "%:"; p2 = patt -> <:patt< $uid:"lazy_cons"$ $p1$ $p2$ >> ] ] ;
 
-    patt: LEVEL "simple" 
+    patt: LEVEL "simple"
       [ [ "[%"; "]" ->
             <:patt< $uid:"lazy_nil"$ >>
-        | "[%"; (n, mk_list) = sem_patt_for_list'; "]" ->
-            <:patt< $uid:"lazy_list"$ $`int:n$ $mk_list <:patt< [] >>$ >> ] ] ;
+        | "[%"; mk_list = sem_patt_for_conses; "]" ->
+            <:patt< $mk_list <:patt< $uid:"lazy_nil"$ >>$ >> ] ] ;
 
-    sem_patt_for_list':
-      [ [ p = patt; ";"; (pn, pl) = SELF -> pn + 1, fun acc -> <:patt< [ $p$ :: $pl acc$ ] >>
-        | p = patt                       -> 1, fun acc -> <:patt< [ $p$ :: $acc$ ] >> ] ] ;
+    sem_patt_for_conses:
+      [ [ p = patt; ";"; pl = SELF -> fun acc -> <:patt< $uid:"lazy_cons"$ $p$ $pl acc$ >>
+        | p = patt                 -> fun acc -> <:patt< $uid:"lazy_cons"$ $p$ $acc$ >> ] ] ;
   END
 
 
   inherit Patterns.extension
   method translate v = function
       <:patt@_loc< $uid:"lazy_nil"$ >> ->
-        Some ( <:expr< Lazy.force $v$ >>,
-               <:patt< Lazy_list.Nil >> )
+        Some (<:expr< Lazy.force $v$ >>, <:patt< Lazy_list.Nil >>)
     | <:patt@_loc< $uid:"lazy_cons"$ $p1$ $p2$ >> ->
-        Some ( <:expr< Lazy.force $v$ >>,
-               <:patt< Lazy_list.Cons ($p1$, $p2$) >> )
-    | <:patt@_loc< $uid:"lazy_list"$ $n$ $pl$ >> ->
-        ( match n with
-            <:patt< $int:limit$>> ->
-              Some ( <:expr< Lazy_list.to_list ~limit:$int:limit$ $v$ >>, pl )
-          | _ -> failwith "[translate] impossible case" )
+        Some (<:expr< Lazy.force $v$ >>, <:patt< Lazy_list.Cons ($p1$, $p2$) >>)
     | _ -> None
 end
 
         [ value_let; r = opt_rec; bi = binding ->
             Patterns.filter <:str_item< value $rec:r$ $bi$ >> ] ] ;
   END
-else
+else begin
+  DELETE_RULE Gram str_item: "let"; opt_rec; binding; "in"; expr END ;
+  DELETE_RULE Gram str_item: "let"; opt_rec; binding END ;
+  DELETE_RULE Gram str_item: "let"; "module"; a_UIDENT; module_binding0; "in"; expr END ;
+
   EXTEND Gram
     GLOBAL: str_item;
 
         | "let"; "module"; m = a_UIDENT; mb = module_binding0; "in"; e = expr ->
              Patterns.filter <:str_item< let module $m$ = $mb$ in $e$ >> ] ] ;
   END
+end
+
+DELETE_RULE Gram str_item: "include"; module_expr END
+DELETE_RULE Gram str_item: "module"; a_UIDENT; module_binding0 END
+DELETE_RULE Gram str_item: "module"; "rec"; module_binding END
+DELETE_RULE Gram str_item: "class"; class_declaration END
+DELETE_RULE Gram str_item: expr END
 
 EXTEND Gram
   GLOBAL: str_item ;
 
-  string_list:
-    [ [ `ANTIQUOT ((""|"str_list"), s) -> Ast.LAnt (mk_anti "str_list" s)
-      | `STRING (_, x); xs = string_list -> Ast.LCons (x, xs)
-      | `STRING (_, x)                   -> Ast.LCons (x, Ast.LNil) ] ]
-  ;
-
   str_item:
     [ "top"
-(**)  [ "exception"; t = constructor_declaration ->
-          Patterns.filter <:str_item< exception $t$ >>
-(**)  | "exception"; t = constructor_declaration; "="; i = type_longident ->
-          Patterns.filter <:str_item< exception $t$ = $i$ >>
-(**)  | "external"; i = a_LIDENT; ":"; t = ctyp; "="; sl = string_list ->
-          Patterns.filter <:str_item< external $i$ : $t$ = $sl$ >>
-(**)  | "include"; me = module_expr -> Patterns.filter <:str_item< include $me$ >>
+      [ "include"; me = module_expr -> Patterns.filter <:str_item< include $me$ >>
       | "module"; i = a_UIDENT; mb = module_binding0 ->
           Patterns.filter <:str_item< module $i$ = $mb$ >>
       | "module"; "rec"; mb = module_binding ->
           Patterns.filter <:str_item< module rec $mb$ >>
-      | "module"; "type"; i = a_UIDENT; "="; mt = module_type ->
-          Patterns.filter <:str_item< module type $i$ = $mt$ >>
-(**)  | "open"; i = module_longident -> Patterns.filter <:str_item< open $i$ >>
-(**)  | "type"; td = type_declaration ->
-          Patterns.filter <:str_item< type $td$ >>
       | "class"; cd = class_declaration ->
           Patterns.filter <:str_item< class $cd$ >>
-      | "class"; "type"; ctd = class_type_declaration ->
-          Patterns.filter <:str_item< class type $ctd$ >>
-      | `ANTIQUOT ((""|"stri"|"anti"|"list" as n), s) ->
-          Patterns.filter <:str_item< $anti:mk_anti ~c:"str_item" n s$ >>
-      | `QUOTATION (x) -> Patterns.filter (Quotation.expand _loc x Quotation.DynAst.str_item_tag)
       | e = expr -> Patterns.filter <:str_item< $exp:e$ >> ] ] ;
 END

tests/test_common.ml

 (* Common functions for unit testing
  *
  * Author: Vadim Shender
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either

tests/test_common.mli

 (* Common functions for unit testing
  *
  * Author: Vadim Shender
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either

tests/test_lazy_list.ml

 (* Lazy lists tests
  *
  * Author: Vadim Shender
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
 let test_make_3 () =
   assert_raises
     (Invalid_argument "Lazy_list.make")
-    ( fun () -> 
+    ( fun () ->
         to_list (make ~limit:(-1) 5) )
 
 let test_make_4 () =
     ~printer:(list_printer string_of_int)
     [9; 8; 7; 6; 5; 4; 3; 2; 1; 0]
     !se
-  
+
 let suite_nth = "nth function test" >::: [ "test 1"  >:: test_nth_1 ;
                                            "test 2"  >:: test_nth_2 ;
                                            "test 3"  >:: test_nth_3 ;
 
 
 let test_partition_1 () =
-  let l1, l2 = partition (( < ) 5) empty in 
+  let l1, l2 = partition (( < ) 5) empty in
   assert_equal
     ~printer:(pair_printer (list_printer string_of_int))
     ([], [])
     (to_list l1, to_list l2)
 
 let test_partition_3 () =
-  let l1, l2 = partition (( < ) 5) (interval 1 9) in 
+  let l1, l2 = partition (( < ) 5) (interval 1 9) in
   assert_equal
     ~printer:(pair_printer (list_printer string_of_int))
     ([6; 7; 8; 9], [1; 2; 3; 4; 5])
 
 
 let test_split_1 () =
-  let l1, l2 = split empty in 
+  let l1, l2 = split empty in
   assert_equal
     ~printer:(pair_printer (list_printer string_of_int))
     ([], [])
     (to_list l1, to_list l2)
 
 let test_split_3 () =
-  let l1, l2 = split (of_list [1, 11; 2, 12; 3, 13; 4, 14; 5, 15]) in 
+  let l1, l2 = split (of_list [1, 11; 2, 12; 3, 13; 4, 14; 5, 15]) in
   assert_equal
     ~printer:(pair_printer (list_printer string_of_int))
     ([1; 2; 3; 4; 5], [11; 12; 13; 14; 15])
         let _ = split_nth (-1) (interval 1 9) in () )
 
 let test_split_nth_6 () =
-  let l1, l2 = split_nth 5 (interval 1 9) in 
+  let l1, l2 = split_nth 5 (interval 1 9) in
   assert_equal
     ~printer:(pair_printer (list_printer string_of_int))
     ([1; 2; 3; 4; 5], [6; 7; 8; 9])

tests/test_llistcomp_orig.ml

 (* Original syntax extension tests
  *
  * Author: Vadim Shender
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
 
 let test_lazy_list_comp_2 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [1, 1; 1, 2; 1, 3; 2, 1; 2, 2; 2, 3]
     (to_list [% i, j | i <- [% 1; 2 ]; j <- [% 1 .. 3 ] ])
 
 let test_lazy_list_comp_3 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [1, 1; 1, 2; 1, 3; 1, 4; 1, 5; 1, 6; 1, 7; 1, 8; 1, 9; 1, 10]
     (to_list ~limit:10 [% i, j | i <- [% 1; 2 ]; j <- [% 1 .. ] ])
 
 let test_lazy_list_comp_4 () =
   assert_equal
+    ~printer:(list_printer (list_printer (pair_printer string_of_int)))
     [[1, 1; 2, 1]; [1, 2; 2, 2]; [1, 3; 2, 3]; [1, 4; 2, 4]; [1, 5; 2, 5]]
     ( List.map to_list
         (to_list ~limit:5 [% [% i, j | i <- [% 1; 2] ] | j <- [% 1 .. ] ]) )
 
 let test_lazy_list_comp_5 () =
   assert_equal
+    ~printer:(list_printer string_of_int)
     [4; 2]
     (to_list [% x | xs <- [% [% 1, 2; 3, 4 ]; [% 5, 4; 3, 2 ] ]; (3, x) <- xs ])
 
     | b -> gcd b (a mod b)
   in
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [2, 1; 3, 1; 3, 2; 4, 1; 4, 3; 5, 1; 5, 2; 5, 3; 5, 4; 6, 1]
-    ( to_list 
+    ( to_list
         ~limit:10
         [% i, j | i <- [% 1 .. ]; j <- [% 1 .. i - 1 ]; gcd i j = 1 ] )
 
 let test_lazy_list_comp_guard_3 () =
   assert_equal
+    ~printer:(list_printer (triplet_printer string_of_int))
     [3, 4, 5; 5, 12, 13; 6, 8, 10; 8, 15, 17; 9, 12, 15; 12, 16, 20]
     (to_list [% x, y, z | x <- [% 1 .. 20 ];
                           y <- [% x .. 20 ];
 
 let test_lazy_list_comp_let_1 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [1, 1; 2, 1; 2, 2; 2, 3; 2, 4; 3, 1; 3, 2; 3, 3; 3, 4; 3, 5]
     ( to_list
         ~limit:10 [% i, j | i <- [% 1 .. ]; let k = i * i; j <- [% 1 .. k ] ] )
 
 let test_lazy_list_comp_let_2 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [2, 4; 3, 9; 4, 16; 5, 25; 6, 36]
     (to_list ~limit:5 [% i, i * i | i <- [% 1 .. ]; let j = i * i; j > 1 ])
 
 let test_lazy_list_comp_let_3 () = ()
 (*
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [1, 1; 2, 4; 3, 9; 4, 16; 5, 25]
     ( to_list
         ~limit:5
 let test_lazy_list_comp_let_4 () = ()
 (*
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [2, 4; 3, 9; 4, 16; 5, 25; 6, 36]
     (to_list ~limit:5 [% i, i * i | i <- [% 1 .. ]; let j = i * i; i > 1 ])
       (* Warning Y: unused variable j. *)
 
 let test_lazy_list_comp_let_5 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [2, 4; 3, 9; 4, 16; 5, 25; 6, 36]
     (to_list ~limit:5 [% i, j | i <- [% 1 .. ]; let j = i * i; i > 1 ])
 
 let test_lazy_list_comp_let_6 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [2, 4; 3, 9; 4, 16; 5, 25; 6, 36]
     (to_list ~limit:5 [% i, j | i <- [% 1 .. ]; let j = i * i; j > 1 ])
 
 let test_lazy_list_comp_let_7 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [1, 1; 2, 1; 2, 2; 2, 3; 2, 4]
     ( to_list
         ~limit:5 [% i, j | i <- [% 1 ..];
 
 let test_lazy_list_comp_let_8 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [1, 1; 2, 16; 3, 81; 4, 256; 5, 625]
     ( to_list
         ~limit:5
 
 let test_lazy_list_comp_let_9 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [1, 1; 2, 16; 3, 81; 4, 256; 5, 625]
     ( to_list
         ~limit:5
 
 let test_lazy_list_comp_let_10 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [3, 81; 4, 256; 5, 625; 6, 1296; 7, 2401]
     ( to_list
         ~limit:5
 
 let test_lazy_list_comp_let_11 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [3, 81; 4, 256; 5, 625; 6, 1296; 7, 2401]
     ( to_list
         ~limit:5
 
 let test_lazy_list_comp_let_12 () =
   assert_equal
+    ~printer:(list_printer (triplet_printer string_of_int))
     [3, 81, 0; 3, 81, 1; 4, 256, 0; 4, 256, 1; 5, 625, 0]
     ( to_list
         ~limit:5
 
 let test_lazy_list_comp_let_13 () =
   assert_equal
+    ~printer:(list_printer (triplet_printer string_of_int))
     [3, 81, 0; 3, 81, 1; 4, 256, 0; 4, 256, 1; 5, 625, 0]
     ( to_list
         ~limit:5
 let test_lazy_list_comp_let_14 () = ()
 (*
   assert_equal
+    ~printer:(list_printer (triplet_printer string_of_int))
     [3, 81, 0; 3, 81, 1; 4, 256, 0; 4, 256, 1; 5, 625, 0]
     ( to_list
         ~limit:5
 
 let test_lazy_list_comp_let_15 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [1, 1; 2, 2; 3, 6; 4, 24; 5, 120]
     ( to_list
         ~limit:5
 
 let test_lazy_list_comp_let_16 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [1, 1; 2, 2; 3, 6; 4, 24; 5, 120]
     ( to_list
         ~limit:5
 
 let test_lazy_list_comp_let_17 () =
   assert_equal
+    ~printer:(list_printer string_of_bool)
     [true; false; true; false; true; false; true; false; true; false]
     (to_list [% odd i | i <- [% 1 .. 10];
                         let rec odd  = function 0 -> false | n -> even (n - 1)
       "test 17" >:: test_lazy_list_comp_let_17 ]
 
 
+let test_lazy_list_comp_parallel_1 () =
+  assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
+    [1, 2; 3, 4; 5, 6; 7, 8; 9, 10]
+    (to_list [% x, y | x <- [% 1; 3 .. 9 ] | y <- [% 2; 4 .. 10 ] ])
+
+let test_lazy_list_comp_parallel_2 () =
+  assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
+    [1, 2; 3, 4; 5, 6; 7, 8; 9, 10]
+    (to_list ~limit:5 [% x, y | x <- [% 1; 3 .. ] | y <- [% 2; 4 .. ] ])
+
+let test_lazy_list_comp_parallel_3 () =
+  assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
+    [1, 2; 3, 4; 5, 6; 7, 8; 9, 10]
+    (to_list [% x, y | x <- [% 1; 3 .. ] | y <- [% 2; 4 .. 10 ] ])
+
+let test_lazy_list_comp_parallel_4 () =
+  assert_equal
+    ~printer:(list_printer (pair_printer (pair_printer string_of_int)))
+    [ (1, 1), (3, 81); (2, 16), (4, 256); (3, 81), (5, 625);
+     (4, 256), (6, 1296); (5, 625), (7, 2401) ]
+    ( to_list
+        ~limit:5
+        [% x, y | x <- [% i, j | i <- [% 1 ..]; i < 10;
+                                 let k = i * i; let j = k * k ]
+                | y <- [% i, j | i <- [% 1 ..]; let k = i * i; let j = k * k;
+                                 i > 2; i < 10 ] ] )
+
+let suite_lazy_list_comp_parallel =
+  "parallel lazy list comprehension test" >:::
+    [ "test 1" >:: test_lazy_list_comp_parallel_1 ;
+      "test 2" >:: test_lazy_list_comp_parallel_2 ;
+      "test 3" >:: test_lazy_list_comp_parallel_3 ;
+      "test 4" >:: test_lazy_list_comp_parallel_4 ]
+
+
 let test_lazy_list_pattern_matching_1 () =
   let primes =
     let rec sieve = function
       suite_lazy_list_comp ;
       suite_lazy_list_comp_guard ;
       suite_lazy_list_comp_let ;
+      suite_lazy_list_comp_parallel ;
       suite_lazy_list_pattern_matching ]
 
 let _ = run_test_tt tests

tests/test_llistcomp_rev.ml

 (* Revised syntax extension tests
  *
  * Author: Vadim Shender
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
 
 value test_lazy_list_comp_2 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [(1, 1); (1, 2); (1, 3); (2, 1); (2, 2); (2, 3)]
     (to_list [% (i, j) | i <- [% 1; 2 ]; j <- [% 1 .. 3 ] ]) ;
 
 value test_lazy_list_comp_3 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [ (1, 1); (1, 2); (1, 3); (1, 4); (1, 5);
       (1, 6); (1, 7); (1, 8); (1, 9); (1, 10) ]
     (to_list ~limit:10 [% (i, j) | i <- [% 1; 2 ]; j <- [% 1 .. ] ]) ;
 
 value test_lazy_list_comp_4 () =
   assert_equal
+    ~printer:(list_printer (list_printer (pair_printer string_of_int)))
     [ [(1, 1); (2, 1)]; [(1, 2); (2, 2)];
       [(1, 3); (2, 3)]; [(1, 4); (2, 4)]; [(1, 5); (2, 5)] ]
     ( List.map to_list
 
 value test_lazy_list_comp_5 () =
   assert_equal
+    ~printer:(list_printer string_of_int)
     [4; 2]
     (to_list [% x | xs <- [% [% (1, 2); (3, 4) ]; [% (5, 4); (3, 2) ] ]; (3, x) <- xs ]) ;
 
     | b -> gcd b (a mod b) ]
   in
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [ (2, 1); (3, 1); (3, 2); (4, 1); (4, 3);
       (5, 1); (5, 2); (5, 3); (5, 4); (6, 1) ]
-    ( to_list 
+    ( to_list
         ~limit:10
         [% (i, j) | i <- [% 1 .. ]; j <- [% 1 .. i - 1 ]; gcd i j = 1 ] ) ;
 
 value test_lazy_list_comp_guard_3 () =
   assert_equal
+    ~printer:(list_printer (triplet_printer string_of_int))
     [ (3, 4, 5); (5, 12, 13); (6, 8, 10);
       (8, 15, 17); (9, 12, 15); (12, 16, 20) ]
     (to_list [% (x, y, z) | x <- [% 1 .. 20 ];
 
 value test_lazy_list_comp_let_1 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [ (1, 1); (2, 1); (2, 2); (2, 3); (2, 4);
       (3, 1); (3, 2); (3, 3); (3, 4); (3, 5) ]
     ( to_list
 
 value test_lazy_list_comp_let_2 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [(2, 4); (3, 9); (4, 16); (5, 25); (6, 36)]
     (to_list ~limit:5 [% (i, i * i) | i <- [% 1 .. ]; let j = i * i; j > 1 ]) ;
 
 value test_lazy_list_comp_let_3 () = () ;
 (*
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [(1, 1); (2, 4); (3, 9); (4, 16); (5, 25)]
     ( to_list
         ~limit:5
 value test_lazy_list_comp_let_4 () = () ;
 (*
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [(2, 4); (3, 9); (4, 16); (5, 25); (6, 36)]
     (to_list ~limit:5 [% (i, i * i) | i <- [% 1 .. ]; let j = i * i; i > 1 ]) ;
       (* Warning Y: unused variable j. *)
 
 value test_lazy_list_comp_let_5 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [(2, 4); (3, 9); (4, 16); (5, 25); (6, 36)]
     (to_list ~limit:5 [% (i, j) | i <- [% 1 .. ]; let j = i * i; i > 1 ]) ;
 
 value test_lazy_list_comp_let_6 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [(2, 4); (3, 9); (4, 16); (5, 25); (6, 36)]
     (to_list ~limit:5 [% (i, j) | i <- [% 1 .. ]; let j = i * i; j > 1 ]) ;
 
 value test_lazy_list_comp_let_7 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [(1, 1); (2, 1); (2, 2); (2, 3); (2, 4)]
     ( to_list
         ~limit:5 [% (i, j) | i <- [% 1 ..];
 
 value test_lazy_list_comp_let_8 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [(1, 1); (2, 16); (3, 81); (4, 256); (5, 625)]
     ( to_list
         ~limit:5
 
 value test_lazy_list_comp_let_9 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [(1, 1); (2, 16); (3, 81); (4, 256); (5, 625)]
     ( to_list
         ~limit:5
 
 value test_lazy_list_comp_let_10 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [(3, 81); (4, 256); (5, 625); (6, 1296); (7, 2401)]
     ( to_list
         ~limit:5
 
 value test_lazy_list_comp_let_11 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [(3, 81); (4, 256); (5, 625); (6, 1296); (7, 2401)]
     ( to_list
         ~limit:5
 
 value test_lazy_list_comp_let_12 () =
   assert_equal
+    ~printer:(list_printer (triplet_printer string_of_int))
     [(3, 81, 0); (3, 81, 1); (4, 256, 0); (4, 256, 1); (5, 625, 0)]
     ( to_list
         ~limit:5
 
 value test_lazy_list_comp_let_13 () =
   assert_equal
+    ~printer:(list_printer (triplet_printer string_of_int))
     [(3, 81, 0); (3, 81, 1); (4, 256, 0); (4, 256, 1); (5, 625, 0)]
     ( to_list
         ~limit:5
 value test_lazy_list_comp_let_14 () = () ;
 (*
   assert_equal
+    ~printer:(list_printer (triplet_printer string_of_int))
     [(3, 81, 0); (3, 81, 1); (4, 256, 0); (4, 256, 1); (5, 625, 0)]
     ( to_list
         ~limit:5
 
 value test_lazy_list_comp_let_15 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [(1, 1); (2, 2); (3, 6); (4, 24); (5, 120)]
     ( to_list
         ~limit:5
 
 value test_lazy_list_comp_let_16 () =
   assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
     [(1, 1); (2, 2); (3, 6); (4, 24); (5, 120)]
     ( to_list
         ~limit:5
 
 value test_lazy_list_comp_let_17 () =
   assert_equal
+    ~printer:(list_printer string_of_bool)
     [True; False; True; False; True; False; True; False; True; False]
     (to_list [% odd i | i <- [% 1 .. 10];
                         let rec odd  = fun [ 0 -> False | n -> even (n - 1) ]
       "test 17" >:: test_lazy_list_comp_let_17 ] ;
 
 
+value test_lazy_list_comp_parallel_1 () =
+  assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
+    [(1, 2); (3, 4); (5, 6); (7, 8); (9, 10)]
+    (to_list [% (x, y) | x <- [% 1; 3 .. 9 ] | y <- [% 2; 4 .. 10 ] ]) ;
+
+value test_lazy_list_comp_parallel_2 () =
+  assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
+    [(1, 2); (3, 4); (5, 6); (7, 8); (9, 10)]
+    (to_list ~limit:5 [% (x, y) | x <- [% 1; 3 .. ] | y <- [% 2; 4 .. ] ]) ;
+
+value test_lazy_list_comp_parallel_3 () =
+  assert_equal
+    ~printer:(list_printer (pair_printer string_of_int))
+    [(1, 2); (3, 4); (5, 6); (7, 8); (9, 10)]
+    (to_list [% (x, y) | x <- [% 1; 3 .. ] | y <- [% 2; 4 .. 10 ] ]) ;
+
+value test_lazy_list_comp_parallel_4 () =
+  assert_equal
+    ~printer:(list_printer (pair_printer (pair_printer string_of_int)))
+    [ ((1, 1), (3, 81)); ((2, 16), (4, 256)); ((3, 81), (5, 625));
+      ((4, 256), (6, 1296)); ((5, 625), (7, 2401)) ]
+    ( to_list
+        ~limit:5
+        [% (x, y) | x <- [% (i, j) | i <- [% 1 ..]; i < 10;
+                                     let k = i * i; let j = k * k ]
+                  | y <- [% (i, j) | i <- [% 1 ..]; let k = i * i;
+                                     let j = k * k; i > 2; i < 10 ] ] ) ;
+
+value suite_lazy_list_comp_parallel =
+  "parallel lazy list comprehension test" >:::
+    [ "test 1" >:: test_lazy_list_comp_parallel_1 ;
+      "test 2" >:: test_lazy_list_comp_parallel_2 ;
+      "test 3" >:: test_lazy_list_comp_parallel_3 ;
+      "test 4" >:: test_lazy_list_comp_parallel_4 ] ;
+
+
 value test_lazy_list_pattern_matching_1 () =
   let primes =
     let rec sieve = fun
       suite_lazy_list_comp ;
       suite_lazy_list_comp_guard ;
       suite_lazy_list_comp_let ;
+      suite_lazy_list_comp_parallel ;
       suite_lazy_list_pattern_matching ] ;
 
 value _ = run_test_tt tests ;
     method unknown : 'a. 'a -> ('self_type * 'a) = fun x -> (o, x)
       
   end
-  
-
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.