(************************************************************************) (* * The Rocq Prover / The Rocq Development Team *) (* v * Copyright INRIA, CNRS and contributors *) (* <O___,, * (see version control and CREDITS file for authors & dates) *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (* * (see LICENSE file for the text of the license) *) (************************************************************************)
(* The interface is an extended version of OCaml stdlib/list.ml. *)
(**************************************************************************) (* *) (* OCaml *) (* *) (* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) (* *) (* Copyright 1996 Institut National de Recherche en Informatique et *) (* en Automatique. *) (* *) (* All rights reserved. This file is distributed under the terms of *) (* the GNU Lesser General Public License version 2.1, with the *) (* special exception on linking described in the file LICENSE. *) (* *) (**************************************************************************)
(** Compute the length of a list. *)
Ltac2 rec length (ls : 'a list) : int := match ls with
| [] => 0
| _ :: xs => Int.add 1 (length xs) end.
(** [compare_lengths ls1 ls2] is equal to [Int.compare (length ls1) (length ls2)], but is more efficient in most cases: it runs in O(min (length ls1) (length ls2))
instead of O(max (length ls1) (length ls2)). *)
Ltac2 rec compare_lengths (ls1 : 'a list) (ls2 : 'b list) : int := match ls1 with
| []
=> match ls2 with
| [] => 0
| _ :: _ => -1 end
| _ :: ls1
=> match ls2 with
| [] => 1
| _ :: ls2 => compare_lengths ls1 ls2 end end.
(** [compare_length_with ls n] is equal to [Int.compare (length ls) n], but is more efficient in most cases: it runs in O(min (length ls) n)
instead of O(length ls). *)
Ltac2 rec compare_length_with (ls : 'a list) (n : int) : int := match Int.lt n 0 with
| true => 1
| false
=> match ls with
| [] => Int.compare 0 n
| _ :: ls => compare_length_with ls (Int.sub n 1) end end.
Ltac2 cons (x : 'a) (xs : 'a list) : 'a list :=
x :: xs.
(** Since Ltac2 distinguishes between backtracking and fatal exceptions, we provide option and default variants of functions which throw in the
OCaml stdlib. *)
(** Return the first element of a list.
Returns [None] if the list is empty. *)
Ltac2 hd_opt (ls : 'a list) : 'a option := match ls with
| [] => None
| x :: _ => Some x end.
(** Return the first element of a list.
Throw an exception if the list is empty. *)
Ltac2 hd (ls : 'a list) : 'a := match ls with
| [] => Control.throw_invalid_argument "List.hd"
| x :: _ => x end.
(** Remove the first element from a list.
The empty list is returned as is. *)
Ltac2 tl (ls : 'a list) : 'a list := match ls with
| [] => []
| _ :: xs => xs end.
(** Destruct a list into its head and tail.
Throws an exception if the list is empty. *)
Ltac2 dest (xs : 'a list) : 'a * 'a list := match xs with
| x :: xs => (x, xs)
| [] => Control.throw_invalid_argument "List.dest: list empty" end.
(** Return [true] if the list is empty. *)
Ltac2 is_empty (xs : 'a list) : bool := match xs with
| _ :: _ => false
| _ => true end.
(** Return the last element of a list.
Returns [None] if the list is empty. *)
Ltac2 rec last_opt (ls : 'a list) : 'a option := match ls with
| [] => None
| x :: xs
=> match xs with
| [] => Some x
| _ :: _ => last_opt xs end end.
(** Return the last element of a list.
Throws an exception if the list is empty. *)
Ltac2 last (ls : 'a list) : 'a := match last_opt ls with
| None => Control.throw_invalid_argument "List.last"
| Some v => v end.
(** Remove the last element of a list.
The empty list is returned as is. *)
Ltac2 rec removelast (ls : 'a list) : 'a list := match ls with
| [] => []
| x :: xs
=> match xs with
| [] => []
| _ :: _ => x :: removelast xs end end.
(** Helper function for [nth_opt]. *)
Ltac2 rec nth_opt_aux (ls : 'a list) (n : int) := match ls with
| [] => None
| x :: xs
=> match Int.equal n 0 with
| true => Some x
| false => nth_opt_aux xs (Int.sub n 1) end end.
(** [nth_opt ls n] returns the [n]-th element [ls], starting at [0].
Throws an exception if [n < 0]. Returns [None] if [n >= length ls]. *)
Ltac2 nth_opt (ls : 'a list) (n : int) : 'a option :=
Control.assert_valid_argument "List.nth" (Int.ge n 0);
nth_opt_aux ls n.
(** [nth ls n] returns the [n]-th element of [ls], starting at [0].
Throws an exception if [n < 0] or [n >= length ls]. *)
Ltac2 nth (ls : 'a list) (n : int) : 'a := match nth_opt ls n with
| Some v => v
| None => Control.throw_out_of_bounds "List.nth" end.
(** Reverse [l1], and append it with [l2]:
[rev_append l1 l2 = append (rev l1) l2]. *)
Ltac2 rec rev_append (l1 : 'a list) (l2 : 'a list) : 'a list := match l1 with
| [] => l2
| a :: l => rev_append l (a :: l2) end.
(** Reverse a list. *)
Ltac2 rev (l : 'a list) : 'a list :=
rev_append l [].
(** Append two lists [ls1] and [ls2]. Complexity: O(length ls1). *)
Ltac2 rec append (ls1 : 'a list) (ls2 : 'a list) : 'a list := match ls1 with
| [] => ls2
| x :: xs => x :: append xs ls2 end.
(** Concatenate a list of lists. *)
Ltac2 rec concat (ls : 'a list list) : 'a list := match ls with
| [] => []
| x :: xs => append x (concat xs) end.
(** Synonym for [concat]. *)
Ltac2 flatten (ls : 'a list list) : 'a list :=
concat ls.
(** Iterate a function on each element of a list.
Elements are processed from first to last. *)
Ltac2 rec iter (f : 'a -> unit) (ls : 'a list) : unit := match ls with
| [] => ()
| l :: ls => f l; iter f ls end.
(** Helper function for [iteri]. *)
Ltac2 rec iteri_aux (i : int) (f : int -> 'a -> unit) (ls : 'a list) : unit := match ls with
| [] => ()
| l :: ls => f i l; iteri_aux (Int.add i 1) f ls end.
(** Iterate a function [f] on each element of a list. [f] is additionally supplied the index of each element, starting at [0].
Elements are processed from first to last. *)
Ltac2 iteri (f : int -> 'a -> unit) (ls : 'a list) : unit :=
iteri_aux 0 f ls.
(** [map f [x0 ; x1 ; ... ; xN]] is [f x0 ; f x1 ; ... ; f xN].
Elements are processed from first to last. *)
Ltac2 rec map (f : 'a -> 'b) (ls : 'a list) : 'b list := match ls with
| [] => []
| l :: ls => f l :: map f ls end.
(** Helper function for [mapi]. *)
Ltac2 rec mapi_aux (i : int) (f : int -> 'a -> 'b) (ls : 'a list) : 'b list := match ls with
| [] => []
| l :: ls => f i l :: mapi_aux (Int.add i 1) f ls end.
(** [mapi f [x0 ; x1 ; ... ; xN]] is [f 0 x0 ; f 1 x1 ; ... ; f N xN].
Elements are processed from first to last. *)
Ltac2 mapi (f : int -> 'a -> 'b) (ls : 'a list) : 'b list :=
mapi_aux 0 f ls.
(** Map a function over a list, and then concatenate the results. *)
Ltac2 rec flat_map (f : 'a -> 'b list) (xs : 'a list) : 'b list := match xs with
| [] => []
| x :: xs => append (f x) (flat_map f xs) end.
(** [rev_map f l] is equal to [rev (map f l)],
but is more efficient in most cases. *)
Ltac2 rev_map (f : 'a -> 'b) (ls : 'a list) : 'b list := let rec rmap_f accu ls := match ls with
| [] => accu
| a::l => rmap_f (f a :: accu) l end in
rmap_f [] ls.
(** [fold_right f [a1; ...; an] init] is [f a1 (f a2 (... (f an init) ...))]. *)
Ltac2 rec fold_right (f : 'a -> 'b -> 'b) (ls : 'a list) (a : 'b) : 'b := match ls with
| [] => a
| l :: ls => f l (fold_right f ls a) end.
(** [fold_left f init [b1; ...; bn]] is [f (... (f (f init b1) b2) ...) bn]. *)
Ltac2 rec fold_left (f : 'a -> 'b -> 'a) (a : 'a) (xs : 'b list) : 'a := match xs with
| [] => a
| x :: xs => fold_left f (f a x) xs end.
Ltac2 fold_lefti (f : int -> 'a -> 'b -> 'a) (a : 'a) (xs : 'b list) : 'a := let rec go i a xs := match xs with
| [] => a
| x :: xs => go (Int.add i 1) (f i a x) xs end
in go 0 a xs.
(** Iterate a function over two lists. Elements are processed from first to last.
Throws an exception if the lengths of the lists differ. *)
Ltac2 rec iter2 (f : 'a -> 'b -> unit) (ls1 : 'a list) (ls2 : 'b list) : unit := match ls1 with
| []
=> match ls2 with
| [] => ()
| _ :: _ => Control.throw_invalid_argument "List.iter2" end
| l1 :: ls1
=> match ls2 with
| [] => Control.throw_invalid_argument "List.iter2"
| l2 :: ls2
=> f l1 l2; iter2 f ls1 ls2 end end.
(** Map a function over two lists. Elements are processed from first to last.
Throws an exception if the lengths of the lists differ. *)
Ltac2 rec map2 (f : 'a -> 'b -> 'c) (ls1 : 'a list) (ls2 : 'b list) : 'c list := match ls1 with
| []
=> match ls2 with
| [] => []
| _ :: _ => Control.throw_invalid_argument "List.map2" end
| l1 :: ls1
=> match ls2 with
| [] => Control.throw_invalid_argument "List.map2"
| l2 :: ls2
=> f l1 l2 :: map2 f ls1 ls2 end end.
(** [rev_map2 f l1 l2] is equal to [rev (map2 f l1 l2)],
but is more efficient in most cases. *)
Ltac2 rev_map2 (f : 'a -> 'b -> 'c) (ls1 : 'a list) (ls2 : 'b list) : 'c list := let rec rmap2_f accu ls1 ls2 := match ls1 with
| []
=> match ls2 with
| [] => accu
| _ :: _ => Control.throw_invalid_argument "List.rev_map2" end
| l1 :: ls1
=> match ls2 with
| [] => Control.throw_invalid_argument "List.rev_map2"
| l2 :: ls2
=> rmap2_f (f l1 l2 :: accu) ls1 ls2 end end in
rmap2_f [] ls1 ls2.
(** Right fold over two lists.
Throws an exception if the lengths of the lists differ. *)
Ltac2 rec fold_right2 (f : 'a -> 'b -> 'c -> 'c) (ls1 : 'a list) (ls2 : 'b list) (a : 'c) : 'c := match ls1 with
| []
=> match ls2 with
| [] => a
| _ :: _ => Control.throw_invalid_argument "List.fold_right2" end
| l1 :: ls1
=> match ls2 with
| [] => Control.throw_invalid_argument "List.fold_right2"
| l2 :: ls2
=> f l1 l2 (fold_right2 f ls1 ls2 a) end end.
(** Left fold over two lists.
Throws an exception if the lengths of the lists differ. *)
Ltac2 rec fold_left2 (f : 'a -> 'b -> 'c -> 'a) (a : 'a) (ls1 : 'b list) (ls2 : 'c list) : 'a := match ls1 with
| []
=> match ls2 with
| [] => a
| _ :: _ => Control.throw_invalid_argument "List.fold_left2" end
| l1 :: ls1
=> match ls2 with
| [] => Control.throw_invalid_argument "List.fold_left2"
| l2 :: ls2
=> fold_left2 f (f a l1 l2) ls1 ls2 end end.
(** [for_all f l] checks that [f] returns true on _all_ elements of the list [l].
In particular [for_all f []] is [true]. *)
Ltac2 rec for_all (f : 'a -> bool) (ls : 'a list) : bool := match ls with
| [] => true
| x :: xs => match f x with
| true => for_all f xs
| false => false end end.
(** [exist f l] checks that [f] returns true on _at least one_ element of the list [l]. In particular [exist f []] is [false].
We would call this [exists] a la OCaml's [List.exists],
but that would be a syntax error (because it conflicts with the notation for tactic `exists`), so instead we name it exist. *)
Ltac2 rec exist (f : 'a -> bool) (ls : 'a list) : bool := match ls with
| [] => false
| x :: xs => match f x with
| true => true
| false => exist f xs end end.
(** Helper function for [for_all2]. *)
Ltac2 rec for_all2_aux (on_length_mismatch : 'a list -> 'b list -> bool) f xs ys : bool := match xs with
| [] => match ys with
| [] => true
| _ :: _ => on_length_mismatch xs ys end
| x :: xs'
=> match ys with
| [] => on_length_mismatch xs ys
| y :: ys'
=> match f x y with
| true => for_all2_aux on_length_mismatch f xs' ys'
| false => false end end end.
(** Same as [for_all] but for two lists.
Throws an exception in case the lengths of the lists differ. *)
Ltac2 for_all2 (f : 'a -> 'b -> bool) (xs : 'a list) (ys : 'b list) : bool :=
for_all2_aux (fun _ _ => Control.throw_invalid_argument "List.for_all2") f xs ys.
(** Same as [for_all] but for two lists.
Returns [false] in case the lengths of the lists differ. *)
Ltac2 equal (f : 'a -> 'b -> bool) (xs : 'a list) (ys : 'b list) : bool :=
for_all2_aux (fun _ _ => false) f xs ys.
(** Same as [exist] but for two lists.
Throws an exception if the lengths of the lists differ. *)
Ltac2 rec exist2 (f : 'a -> 'b -> bool) (xs : 'a list) (ys : 'b list) : bool := match xs with
| [] => match ys with
| [] => false
| _ :: _ => Control.throw_invalid_argument "List.exist2" end
| x :: xs'
=> match ys with
| [] => Control.throw_invalid_argument "List.exist2"
| y :: ys'
=> match f x y with
| true => true
| false => exist2 f xs' ys' end end end.
(** [find_opt f xs] returns the _first_ element of the list [xs] satisfying [f].
Returns [None] if no element is found. *)
Ltac2 rec find_opt (f : 'a -> bool) (xs : 'a list) : 'a option := match xs with
| [] => None
| x :: xs => match f x with
| true => Some x
| false => find_opt f xs end end.
(** [find f xs] returns the _first_ element of the list [xs] satisfying [f].
Throws an exception if no element is found. *)
Ltac2 find (f : 'a -> bool) (xs : 'a list) : 'a := match find_opt f xs with
| Some v => v
| None => Control.throw Not_found end.
(** [find_rev_opt f xs] returns the _last_ element of the list [xs] satisfying [f].
Returns [None] if no element is found. *)
Ltac2 rec find_rev_opt (f : 'a -> bool) (xs : 'a list) : 'a option := match xs with
| [] => None
| x :: xs => match find_rev_opt f xs with
| Some v => Some v
| None => match f x with
| true => Some x
| false => None end end end.
(** [find_rev f xs] returns the _last_ element of the list [xs] satisfying [f].
Throws an exception if no element is found. *)
Ltac2 find_rev (f : 'a -> bool) (xs : 'a list) : 'a := match find_rev_opt f xs with
| Some v => v
| None => Control.throw Not_found end.
(** [mem eq a ls] checks if an element of [ls] is equal to [a] according
to the user-supplied equality function [eq]. *)
Ltac2 mem (eq : 'a -> 'a -> bool) (a : 'a) (ls : 'a list) : bool := exist (eq a) ls.
(** [filter f xs] removes all the elements of [xs] which do not satisfy [f]. *)
Ltac2 rec filter (f : 'a -> bool) (xs : 'a list) : 'a list := match xs with
| [] => []
| x :: xs
=> match f x with
| true => x :: filter f xs
| false => filter f xs end end.
(** [filter_out f xs] removes all the elements of [xs] which satisfy [f]. *)
Ltac2 rec filter_out (f : 'a -> bool) (xs : 'a list) : 'a list :=
filter (fun x => Bool.neg (f x)) xs.
(** Synonym for [filter]. *)
Ltac2 find_all (f : 'a -> bool) (ls : 'a list) : 'a list := filter f ls.
(** [remove eqb x ls] removes all elements of [ls] which are equal to [x],
according to the user-supplied equality function [eqb]. *)
Ltac2 remove (eqb : 'a -> 'a -> bool) (x : 'a) (ls : 'a list) : 'a list :=
filter_out (eqb x) ls.
(** [count_occ eqb x ls] counts how many elements of [ls] are equal to [x], according
to the user-supplied equality function [eqb]. *)
Ltac2 count_occ (eqb : 'a -> 'a -> bool) (x : 'a) (ls : 'a list) : int :=
length (filter (eqb x) ls).
(** [list_power ls1 ls2] is [ls2]^[ls1], or the set of sequences of elements
of [ls2] indexed by elements of [ls1], sorted in lexicographic order. *)
Ltac2 rec list_power (ls1 : 'a list) (ls2 : 'b list) : ('a * 'b) list list := match ls1 with
| [] => [] :: []
| x :: t
=> flat_map (fun f => map (fun y => (x, y) :: f) ls2)
(list_power t ls2) end.
(** [partition f l] returns two lists [(l_true, l_false)] such that: - [l_true] is the sublist of elements of [l] which satisfy [f].
- [l_false] is the sublist of elements of [l] which do not satisfy [f]. *)
Ltac2 rec partition (f : 'a -> bool) (l : 'a list) : 'a list * 'a list := match l with
| [] => ([], [])
| x :: tl
=> let (g, d) := partition f tl in match f x with
| true => ((x::g), d)
| false => (g, (x::d)) end end.
(** [list_prod ls1 ls2] returns the cartesian product of [ls1] and [ls2],
i.e. the list of _all_ pairs [(x, y)] where [x] is in [ls1] and [y] is in [ls2]. *)
Ltac2 rec list_prod (ls1 : 'a list) (ls2 : 'b list) : ('a * 'b) list := match ls1 with
| [] => []
| x :: t
=> append (map (fun y => (x, y)) ls2) (list_prod t ls2) end.
(** [fistn n ls] returns the first [n] elements of [ls].
Throws an exception if [n < 0] or [n > length ls]. *)
Ltac2 rec firstn (n : int) (ls : 'a list) : 'a list :=
Control.assert_valid_argument "List.firstn" (Int.ge n 0); match Int.equal n 0 with
| true => []
| false
=> match ls with
| [] => Control.throw_out_of_bounds "List.firstn"
| x :: xs
=> x :: firstn (Int.sub n 1) xs end end.
(** [skipn n ls] removes the first [n] elements of [ls].
Throws an exception if [n < 0] or [n > length ls]. *)
Ltac2 rec skipn (n : int) (ls : 'a list) : 'a list :=
Control.assert_valid_argument "List.skipn" (Int.ge n 0); match Int.equal n 0 with
| true => ls
| false
=> match ls with
| [] => Control.throw_out_of_bounds "List.skipn"
| _ :: xs
=> skipn (Int.sub n 1) xs end end.
(** [lastn n ls] returns the last [n] elements of [ls].
Throws an exception if [n < 0] or [n > length ls]. *)
Ltac2 lastn (n : int) (ls : 'a list) : 'a list := let l := length ls in
Control.assert_valid_argument "List.lastn" (Int.ge n 0);
Control.assert_bounds "List.lastn" (Int.le n l);
skipn (Int.sub l n) ls.
(** [nodup eqb ls] removes duplicates from [ls], according
to the user-suppplied equality function [eq]. *)
Ltac2 rec nodup (eqb : 'a -> 'a -> bool) (ls : 'a list) : 'a list := match ls with
| [] => []
| x :: xs
=> match mem eqb x xs with
| true => nodup eqb xs
| false => x :: nodup eqb xs end end.
(** [seq start step last] returns the list [start ; (start + step) ; (start + 2*step) ; ...], stopping when [start + n*step >= last]. In particular the lower bound [start] is included,
whereas the upper bound [last] is excluded. *)
Ltac2 rec seq (start : int) (step : int) (last : int) : int list := match Int.lt (Int.sub last start) step with
| true
=> []
| false
=> start :: seq (Int.add start step) step last end.
(** [init n f] returns the list [f 0 ; f 1 ; ... ; f (n-1)].
Throws an exception if [n < 0]. *)
Ltac2 init (n : int) (f : int -> 'a) : 'a list :=
Control.assert_valid_argument "List.init" (Int.ge n 0);
map f (seq 0 1 n).
(** [repeat x n] returns the list of length [n] with all elements equal to [x]. *)
Ltac2 repeat (x : 'a) (n : int) : 'a list :=
init n (fun _ => x).
(** [assoc eqk k l] returns the first value associated to key [k] in an association list [l], using [eqk] to compare keys for equality.
Throws an exception if no value is found. *)
Ltac2 assoc (eqk : 'k -> 'k -> bool) (k : 'k) (l : ('k * 'v) list) : 'v := let eq_key kv := let (k', _) := kv in eqk k k' in let (_, v) := find eq_key l in
v.
(** [assoc eqk k l] returns the first value associated to key [k] in an association list [l], using [eqk] to compare keys for equality.
Returns [None] if no value is found. *)
Ltac2 assoc_opt (eqk : 'k -> 'k -> bool) (k : 'k) (l : ('k * 'v) list) : 'v option := let eq_key kv := let (k', _) := kv in eqk k k' in match find_opt eq_key l with
| Some kv => let (_, v) := kv in Some v
| None => None end.
(** [mem_assoc eqk k l] checks if the key [k] is present in an association list [l],
using [eqk] to compare keys for equality. *)
Ltac2 mem_assoc (eqk : 'k -> 'k -> bool) (k : 'k) (l : ('k * 'v) list) : bool := let eq_key kv := let (k', _) := kv in eqk k k' in exist eq_key l.
(** [remove_assoc eqk k l] removes _all_ key/value pairs associated with key [k]
from an association list [l], using [eqk] to compare keys for equality. *)
Ltac2 remove_assoc (eqk : 'k -> 'k -> bool) (k : 'k) (l : ('k * 'v) list) : ('k * 'v) list := let eq_key kv := let (k', _) := kv in eqk k k' in
filter_out eq_key l.
(** Split a list of pairs into a pair of lists. *)
Ltac2 rec split (ls : ('a * 'b) list) : 'a list * 'b list := match ls with
| [] => ([], [])
| xy :: tl
=> let (x, y) := xy in let (left, right) := split tl in
((x::left), (y::right)) end.
(** Combine two lists into a list of pairs. Only pairs of elements at the same position are considered.
Throws an exception if the lengths of the lists differ. *)
Ltac2 rec combine (ls1 : 'a list) (ls2 : 'b list) : ('a * 'b) list := match ls1 with
| []
=> match ls2 with
| [] => []
| _ :: _ => Control.throw_invalid_argument "List.combine" end
| x :: xs
=> match ls2 with
| y :: ys
=> (x, y) :: combine xs ys
| [] => Control.throw_invalid_argument "List.combine" end end.
(** [enumerate [x0 ; x1 ; x2 ; ...]] returns the list [(0, x0) ; (1, x1) ; (2, x2) ; ...]. *)
Ltac2 enumerate (ls : 'a list) :=
mapi (fun i v => (i,v)) ls.
(** Merge two list sorted in increasing order into a sorted list,
using a user-provided comparison function. *)
Ltac2 rec merge (cmp : 'a -> 'a -> int) (l1 : 'a list) (l2 : 'a list) : 'a list := let rec merge_aux l2 := match l1 with
| [] => l2
| a1 :: l1'
=> match l2 with
| [] => l1
| a2 :: l2'
=> match Int.le (cmp a1 a2) 0 with
| true => a1 :: merge cmp l1' l2
| false => a2 :: merge_aux l2' end end end in
merge_aux l2.
Ltac2 rec merge_list_to_stack cmp stack l := match stack with
| [] => [Some l]
| l' :: stack'
=> match l' with
| None => Some l :: stack'
| Some l'
=> None :: merge_list_to_stack cmp stack' (merge cmp l' l) end end.
Ltac2 rec merge_stack cmp stack := match stack with
| [] => []
| l :: stack'
=> match l with
| None => merge_stack cmp stack'
| Some l => merge cmp l (merge_stack cmp stack') end end.
Ltac2 rec iter_merge cmp stack l := match l with
| [] => merge_stack cmp stack
| a::l' => iter_merge cmp (merge_list_to_stack cmp stack [a]) l' end.
(** [sort cmp l] sorts the list [l] in increasing order, according to the user-supplied comparison function [cmp].
It is currently implemented using a variant of merge sort. *)
Ltac2 sort (cmp : 'a -> 'a -> int) (l : 'a list) : 'a list :=
iter_merge cmp [] l.
(** [sort cmp l] sorts the list [l] in increasing order and removes duplicates, according to the user-supplied comparison function [cmp].
This takes advantage of the fact that removing duplicates from a sorted list
is much faster than for an arbitrary list. *)
Ltac2 sort_uniq (cmp : 'a -> 'a -> int) (l : 'a list) : 'a list := let rec uniq l := match l with
| [] => []
| x1 :: xs
=> match xs with
| [] => x1 :: xs
| x2 :: _
=> match Int.equal (cmp x1 x2) 0 with
| true => uniq xs
| false => x1 :: uniq xs end end end in
uniq (sort cmp l).
(** [inclusive_range lb ub] returns the list [lb ; lb+1 ; lb+2 ; ... ; up].
In particular both the lower bound [lb] and upper bound [ub] are included. *)
Ltac2 inclusive_range (lb : int) (ub : int) : int list :=
seq lb 1 (Int.add ub 1).
(** [range lb ub] returns the list [lb ; lb+1 ; lb+2 ; ... ; up-1].
In particular the lower bound [lb] is included, whereas the upper bound [ub] is excluded. *)
Ltac2 range (lb : int) (ub : int) : int list :=
seq lb 1 ub.
(** [concat_rev [x1; ..; xN-1; xN]] computes [rev xN ++ rev xN-1 ++ .. ++ x1]. Note that [x1] is not reversed and appears in its original order.
[concat_rev] is faster than [concat] and should be preferred over [concat]
when the order of items does not matter. *)
Ltac2 concat_rev (ls : 'a list list) : 'a list := let rec go ls acc := match ls with
| [] => acc
| l :: ls => go ls (rev_append l acc) end
in match ls with
| [] => []
| l :: ls => go ls l end.
(** [map_filter f l] maps [f] over [l], then removes all elements that are [None]. *)
Ltac2 rec map_filter (f : 'a -> 'b option) (l : 'a list) : 'b list := match l with
| [] => []
| x :: l => match f x with
| Some y => y :: map_filter f l
| None => map_filter f l end end.
Messung V0.5
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.2Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.