@ -7,45 +7,20 @@
(* * Terms *)
(* * Terms *)
(* * Representation of Arithmetic terms *)
(* Define term type using polymorphic arithmetic type, with derived compare,
module rec Arith0 :
equal , and sexp_of functions * )
( Arithmetic . REPRESENTATION
module Trm1 = struct
with type var := Trm . Var1 . t
type compare [ @@ deriving compare , equal , sexp ]
with type trm := Trm . t ) =
Arithmetic . Representation
( Trm . Var1 )
( struct
include Trm
include Comparer . Make ( Trm )
end )
(* * Arithmetic terms *)
and Arith : ( Arithmetic . S with type trm := Trm . t with type t = Arith0 . t ) =
struct
include Arith0
include Make ( struct
type arith = ( t , compare ) Arithmetic . t
let to_trm = Trm . _Arith
let get_arith ( e : Trm . t ) =
match e with
| Z z -> Some ( Arith . const ( Q . of_z z ) )
| Q q -> Some ( Arith . const q )
| Arith a -> Some a
| _ -> None
end )
end
(* * Terms, built from variables and applications of function symbols from
and t =
various theories . Denote functions from structures to values . * )
and Trm : sig
type t = private
(* variables *)
(* variables *)
| Var of { id : int ; name : string }
| Var of { id : int ; name : string [ @ ignore ] }
(* arithmetic *)
(* arithmetic *)
| Z of Z . t
| Z of Z . t
| Q of Q . t
| Q of Q . t
| Arith of Arith . t
| Arith of arith
(* sequences ( of flexible size ) *)
(* sequences ( of flexible size ) *)
| Splat of t
| Splat of t
| Sized of { seq : t ; siz : t }
| Sized of { seq : t ; siz : t }
@ -54,50 +29,20 @@ and Trm : sig
(* uninterpreted *)
(* uninterpreted *)
| Apply of Funsym . t * t array
| Apply of Funsym . t * t array
[ @@ deriving compare , equal , sexp ]
[ @@ deriving compare , equal , sexp ]
end
(* * Variable terms, represented as a subtype of general terms *)
(* Add comparer, needed to instantiate arithmetic and containers *)
module Var1 : sig
module Trm2 = struct
type trm := t
include Comparer . Counterfeit ( Trm1 )
include Trm1
end
include Var_intf . S with type t = private trm
(* Specialize arithmetic type and define operations using comparer *)
module Arith0 = Arithmetic . Make ( Trm2 )
val of_ : trm -> t
(* Add ppx, defined recursively with Arith0.ppx *)
val of_trm : trm -> t option
module Trm3 = struct
end
include Trm2
val ppx : Var1 . strength -> t pp
val pp : t pp
include Invariant . S with type t := t
val _ Var : int -> string -> t
val _ Z : Z . t -> t
val _ Q : Q . t -> t
val _ Arith : Arith . t -> t
val _ Splat : t -> t
val _ Sized : seq : t -> siz : t -> t
val _ Extract : seq : t -> off : t -> len : t -> t
val _ Concat : t array -> t
val _ Apply : Funsym . t -> t array -> t
val add : t -> t -> t
val sub : t -> t -> t
val seq_size_exn : t -> t
val seq_size : t -> t option
val get_z : t -> Z . t option
val get_q : t -> Q . t option
val vars : t -> Var1 . t iter
end = struct
type t =
| Var of { id : int ; name : string [ @ ignore ] }
| Z of Z . t
| Q of Q . t
| Arith of Arith . t
| Splat of t
| Sized of { seq : t ; siz : t }
| Extract of { seq : t ; off : t ; len : t }
| Concat of t array
| Apply of Funsym . t * t array
[ @@ deriving compare , equal , sexp ]
(* nul-terminated string value represented by a concatenation *)
(* nul-terminated string value represented by a concatenation *)
let string_of_concat xs =
let string_of_concat xs =
@ -136,7 +81,7 @@ end = struct
| Some ` Anonymous -> Trace . pp_styled ` Cyan " _ " fs )
| Some ` Anonymous -> Trace . pp_styled ` Cyan " _ " fs )
| Z z -> Trace . pp_styled ` Magenta " %a " fs Z . pp z
| Z z -> Trace . pp_styled ` Magenta " %a " fs Z . pp z
| Q q -> Trace . pp_styled ` Magenta " %a " fs Q . pp q
| Q q -> Trace . pp_styled ` Magenta " %a " fs Q . pp q
| Arith a -> Arith . ppx ( ppx strength ) fs a
| Arith a -> Arith 0 . ppx ( ppx strength ) fs a
| Splat x -> pf " %a^ " pp x
| Splat x -> pf " %a^ " pp x
| Sized { seq ; siz } -> pf " @<1>⟨%a,%a@<1>⟩ " pp siz pp seq
| Sized { seq ; siz } -> pf " @<1>⟨%a,%a@<1>⟩ " pp siz pp seq
| Extract { seq ; off ; len } -> pf " %a[%a,%a) " pp seq pp off pp len
| Extract { seq ; off ; len } -> pf " %a[%a,%a) " pp seq pp off pp len
@ -157,19 +102,31 @@ end = struct
pp fs trm
pp fs trm
let pp = ppx ( fun _ -> None )
let pp = ppx ( fun _ -> None )
let pp_diff fs ( x , y ) = Format . fprintf fs " -- %a ++ %a " pp x pp y
end
(* Define containers over terms *)
module Set = struct
include Set . Make ( Trm3 )
include Provide_of_sexp ( Trm3 )
include Provide_pp ( Trm3 )
end
module Map = struct
include Map . Make ( Trm3 )
include Provide_of_sexp ( Trm3 )
end
(* Define variables as a subtype of terms *)
module Var = struct
open Trm3
(* Define variables as a subtype of terms *)
module Var1 = struct
module V = struct
module V = struct
module T = struct
type nonrec t = t [ @@ deriving compare , equal , sexp ]
type nonrec t = t [ @@ deriving compare , equal , sexp ]
type strength = t -> [ ` Universal | ` Existential | ` Anonymous ] option
type strength = t -> [ ` Universal | ` Existential | ` Anonymous ] option
let pp = pp
let pp = pp
let ppx = ppx
let ppx = ppx
end
include T
let invariant x =
let invariant x =
let @ () = Invariant . invariant [ % here ] x [ % sexp_of : t ] in
let @ () = Invariant . invariant [ % here ] x [ % sexp_of : t ] in
@ -182,22 +139,16 @@ end = struct
let name = function Var v -> v . name | x -> violates invariant x
let name = function Var v -> v . name | x -> violates invariant x
module Set = struct
module Set = struct
module S = NS . Set . Make ( T )
include Set
include S
include Provide_of_sexp ( T )
include Provide_pp ( T )
let ppx strength vs = S . pp_full ( ppx strength ) vs
let ppx strength vs = pp_full ( ppx strength ) vs
let pp_xs fs xs =
let pp_xs fs xs =
if not ( is_empty xs ) then
if not ( is_empty xs ) then
Format . fprintf fs " @<2>∃ @[%a@] .@;<1 2> " pp xs
Format . fprintf fs " @<2>∃ @[%a@] .@;<1 2> " pp xs
end
end
module Map = struct
module Map = Map
include NS . Map . Make ( T )
include Provide_of_sexp ( T )
end
let fresh name ~ wrt =
let fresh name ~ wrt =
let max =
let max =
@ -219,26 +170,44 @@ end = struct
include V
include V
module Subst = Subst . Make ( V )
module Subst = Subst . Make ( V )
end
end
(* Add definitions needed for arithmetic embedding into terms *)
module Trm = struct
include Trm3
(* * Invariant *)
let invariant e =
let invariant e =
let @ () = Invariant . invariant [ % here ] e [ % sexp_of : t ] in
let @ () = Invariant . invariant [ % here ] e [ % sexp_of : t ] in
match e with
match e with
| Q q -> assert ( not ( Z . equal Z . one ( Q . den q ) ) )
| Q q -> assert ( not ( Z . equal Z . one ( Q . den q ) ) )
| Arith a -> (
| Arith a -> (
match Arith . classify a with
match Arith 0 . classify a with
| Trm _ | Const _ -> assert false
| Trm _ | Const _ -> assert false
| _ -> () )
| _ -> () )
| _ -> ()
| _ -> ()
(* * Destruct *)
(* * Traverse *)
let get_z = function Z z -> Some z | _ -> None
let rec iter_vars e ~ f =
let get_q = function Q q -> Some q | Z z -> Some ( Q . of_z z ) | _ -> None
match e with
| Var _ as v -> f ( Var . of_ v )
| Z _ | Q _ -> ()
| Splat x -> iter_vars ~ f x
| Sized { seq = x ; siz = y } ->
iter_vars ~ f x ;
iter_vars ~ f y
| Extract { seq = x ; off = y ; len = z } ->
iter_vars ~ f x ;
iter_vars ~ f y ;
iter_vars ~ f z
| Concat xs | Apply ( _ , xs ) -> Array . iter ~ f : ( iter_vars ~ f ) xs
| Arith a -> Iter . iter ~ f : ( iter_vars ~ f ) ( Arith0 . trms a )
(* * Construct *)
let vars e = Iter . from_labelled_iter ( iter_vars e )
let _ Var id name = Var { id ; name } | > check invariant
(* * Construct *)
(* statically allocated since they are tested with == *)
(* statically allocated since they are tested with == *)
let zero = Z Z . zero | > check invariant
let zero = Z Z . zero | > check invariant
@ -253,20 +222,63 @@ end = struct
| > check invariant
| > check invariant
let _ Arith a =
let _ Arith a =
( match Arith . classify a with
( match Arith 0 . classify a with
| Trm e -> e
| Trm e -> e
| Const q -> _ Q q
| Const q -> _ Q q
| _ -> Arith a )
| _ -> Arith a )
| > check invariant
| > check invariant
end
include Trm
(* Instantiate arithmetic with embedding into terms, yielding full
Arithmetic interface * )
module Arith =
Arith0 . Embed ( Var ) ( Trm )
( struct
let to_trm = _ Arith
let get_arith e =
match e with
| Z z -> Some ( Arith0 . const ( Q . of_z z ) )
| Q q -> Some ( Arith0 . const q )
| Arith a -> Some a
| _ -> None
end )
(* Full Trm definition, using full arithmetic interface *)
(* * Destruct *)
let get_z = function Z z -> Some z | _ -> None
let get_q = function Q q -> Some q | Z z -> Some ( Q . of_z z ) | _ -> None
(* * Construct *)
let add x y = _ Arith Arith . ( add ( trm x ) ( trm y ) )
(* variables *)
let sub x y = _ Arith Arith . ( sub ( trm x ) ( trm y ) )
let var v = ( v : Var . t :> t )
(* arithmetic *)
let integer z = _ Z z
let rational q = _ Q q
let neg x = _ Arith Arith . ( neg ( trm x ) )
let add x y = _ Arith Arith . ( add ( trm x ) ( trm y ) )
let sub x y = _ Arith Arith . ( sub ( trm x ) ( trm y ) )
let mulq q x = _ Arith Arith . ( mulc q ( trm x ) )
let mul x y = _ Arith ( Arith . mul x y )
let div x y = _ Arith ( Arith . div x y )
let pow x i = _ Arith ( Arith . pow x i )
let arith = _ Arith
let _ Splat x =
(* sequences *)
let splat x =
(* 0^ ==> 0 *)
(* 0^ ==> 0 *)
( if x = = zero then x else Splat x ) | > check invariant
( if x = = zero then x else Splat x ) | > check invariant
let seq_size_exn =
let seq_size_exn =
let invalid = Invalid_argument " seq_size_exn " in
let invalid = Invalid_argument " seq_size_exn " in
let rec seq_size_exn = function
let rec seq_size_exn = function
| Sized { siz = n } | Extract { len = n } -> n
| Sized { siz = n } | Extract { len = n } -> n
@ -276,28 +288,27 @@ end = struct
in
in
seq_size_exn
seq_size_exn
let seq_size e =
let seq_size e = try Some ( seq_size_exn e ) with Invalid_argument _ -> None
try Some ( seq_size_exn e ) with Invalid_argument _ -> None
let _ S ized ~ seq ~ siz =
let s ized ~ seq ~ siz =
( match seq_size seq with
( match seq_size seq with
(* ⟨n,α⟩ ==> α when n ≡ |α | *)
(* ⟨n,α⟩ ==> α when n ≡ |α | *)
| Some n when equal siz n -> seq
| Some n when equal siz n -> seq
| _ -> Sized { seq ; siz } )
| _ -> Sized { seq ; siz } )
| > check invariant
| > check invariant
let partial_compare x y =
let partial_compare x y =
match sub x y with
match sub x y with
| Z z -> Some ( Int . sign ( Z . sign z ) )
| Z z -> Some ( Int . sign ( Z . sign z ) )
| Q q -> Some ( Int . sign ( Q . sign q ) )
| Q q -> Some ( Int . sign ( Q . sign q ) )
| _ -> None
| _ -> None
let partial_ge x y =
let partial_ge x y =
match partial_compare x y with Some ( Pos | Zero ) -> true | _ -> false
match partial_compare x y with Some ( Pos | Zero ) -> true | _ -> false
let empty_seq = Concat [| |]
let empty_seq = Concat [| |]
let rec _ E xtract ~ seq ~ off ~ len =
let rec e xtract ~ seq ~ off ~ len =
[ % trace ]
[ % trace ]
~ call : ( fun { pf } -> pf " @ %a " pp ( Extract { seq ; off ; len } ) )
~ call : ( fun { pf } -> pf " @ %a " pp ( Extract { seq ; off ; len } ) )
~ retn : ( fun { pf } -> pf " %a " pp )
~ retn : ( fun { pf } -> pf " %a " pp )
@ -309,13 +320,13 @@ end = struct
match seq with
match seq with
(* α [m,k ) [o,l ) ==> α [m+o,l ) when k ≥ o+l *)
(* α [m,k ) [o,l ) ==> α [m+o,l ) when k ≥ o+l *)
| Extract { seq = a ; off = m ; len = k } when partial_ge k o_l ->
| Extract { seq = a ; off = m ; len = k } when partial_ge k o_l ->
_ E xtract ~ seq : a ~ off : ( add m off ) ~ len
e xtract ~ seq : a ~ off : ( add m off ) ~ len
(* ⟨n,0⟩[o,l ) ==> ⟨l,0⟩ when n ≥ o+l *)
(* ⟨n,0⟩[o,l ) ==> ⟨l,0⟩ when n ≥ o+l *)
| Sized { siz = n ; seq } when seq = = zero && partial_ge n o_l ->
| Sized { siz = n ; seq } when seq = = zero && partial_ge n o_l ->
_ S ized ~ seq ~ siz : len
s ized ~ seq ~ siz : len
(* ⟨n,E^⟩[o,l ) ==> ⟨l,E^⟩ when n ≥ o+l *)
(* ⟨n,E^⟩[o,l ) ==> ⟨l,E^⟩ when n ≥ o+l *)
| Sized { siz = n ; seq = Splat _ as e } when partial_ge n o_l ->
| Sized { siz = n ; seq = Splat _ as e } when partial_ge n o_l ->
_ S ized ~ seq : e ~ siz : len
s ized ~ seq : e ~ siz : len
(* ⟨n,a⟩[0,n ) ==> ⟨n,a⟩ *)
(* ⟨n,a⟩[0,n ) ==> ⟨n,a⟩ *)
| Sized { siz = n } when equal off zero && equal n len -> seq
| Sized { siz = n } when equal off zero && equal n len -> seq
(* For ( α₀^α₁ ) [o,l ) there are 3 cases:
(* For ( α₀^α₁ ) [o,l ) there are 3 cases:
@ -344,7 +355,7 @@ end = struct
Array . fold_map_until na1N ( l , off )
Array . fold_map_until na1N ( l , off )
~ f : ( fun naI ( l , oI ) ->
~ f : ( fun naI ( l , oI ) ->
if Z . equal Z . zero l then
if Z . equal Z . zero l then
` Continue ( _ E xtract ~ seq : naI ~ off : oI ~ len : zero , ( l , oI ) )
` Continue ( e xtract ~ seq : naI ~ off : oI ~ len : zero , ( l , oI ) )
else
else
let nI = seq_size_exn naI in
let nI = seq_size_exn naI in
let oI_nI = sub oI nI in
let oI_nI = sub oI nI in
@ -354,15 +365,15 @@ end = struct
let lI = Z . ( max zero ( min l ( neg z ) ) ) in
let lI = Z . ( max zero ( min l ( neg z ) ) ) in
let l = Z . ( l - lI ) in
let l = Z . ( l - lI ) in
` Continue
` Continue
( _ E xtract ~ seq : naI ~ off : oI ~ len : ( _ Z lI ) , ( l , oJ ) )
( e xtract ~ seq : naI ~ off : oI ~ len : ( _ Z lI ) , ( l , oJ ) )
| _ -> ` Stop ( Extract { seq ; off ; len } ) )
| _ -> ` Stop ( Extract { seq ; off ; len } ) )
~ finish : ( fun ( e1N , _ ) -> _ C oncat e1N )
~ finish : ( fun ( e1N , _ ) -> c oncat e1N )
| _ -> Extract { seq ; off ; len } )
| _ -> Extract { seq ; off ; len } )
(* α [o,l ) *)
(* α [o,l ) *)
| _ -> Extract { seq ; off ; len } )
| _ -> Extract { seq ; off ; len } )
| > check invariant
| > check invariant
and _ C oncat xs =
and c oncat xs =
[ % trace ]
[ % trace ]
~ call : ( fun { pf } -> pf " @ %a " pp ( Concat xs ) )
~ call : ( fun { pf } -> pf " @ %a " pp ( Concat xs ) )
~ retn : ( fun { pf } -> pf " %a " pp )
~ retn : ( fun { pf } -> pf " %a " pp )
@ -380,102 +391,29 @@ end = struct
, Extract { seq = na' ; off = o_k ; len = l } )
, Extract { seq = na' ; off = o_k ; len = l } )
when equal na na' && equal o_k ( add o k ) && partial_ge n ( add o_k l )
when equal na na' && equal o_k ( add o k ) && partial_ge n ( add o_k l )
->
->
Some ( _ E xtract ~ seq : na ~ off : o ~ len : ( add k l ) )
Some ( e xtract ~ seq : na ~ off : o ~ len : ( add k l ) )
(* ⟨m,0⟩^⟨n,0⟩ ==> ⟨m+n,0⟩ *)
(* ⟨m,0⟩^⟨n,0⟩ ==> ⟨m+n,0⟩ *)
| Sized { siz = m ; seq = a } , Sized { siz = n ; seq = a' }
| Sized { siz = m ; seq = a } , Sized { siz = n ; seq = a' }
when a = = zero && a' = = zero ->
when a = = zero && a' = = zero ->
Some ( _ S ized ~ seq : a ~ siz : ( add m n ) )
Some ( s ized ~ seq : a ~ siz : ( add m n ) )
(* ⟨m,E^⟩^⟨n,E^⟩ ==> ⟨m+n,E^⟩ *)
(* ⟨m,E^⟩^⟨n,E^⟩ ==> ⟨m+n,E^⟩ *)
| Sized { siz = m ; seq = Splat _ as a } , Sized { siz = n ; seq = a' }
| Sized { siz = m ; seq = Splat _ as a } , Sized { siz = n ; seq = a' }
when equal a a' ->
when equal a a' ->
Some ( _ S ized ~ seq : a ~ siz : ( add m n ) )
Some ( s ized ~ seq : a ~ siz : ( add m n ) )
| _ -> None
| _ -> None
in
in
let xs = flatten xs in
let xs = flatten xs in
let xs = Array . reduce_adjacent ~ f : simp_adjacent xs in
let xs = Array . reduce_adjacent ~ f : simp_adjacent xs in
( if Array . length xs = 1 then xs . ( 0 ) else Concat xs ) | > check invariant
( if Array . length xs = 1 then xs . ( 0 ) else Concat xs ) | > check invariant
let _ Apply f es =
(* uninterpreted *)
let apply f es =
( match Funsym . eval ~ equal ~ get_z ~ ret_z : _ Z ~ get_q ~ ret_q : _ Q f es with
( match Funsym . eval ~ equal ~ get_z ~ ret_z : _ Z ~ get_q ~ ret_q : _ Q f es with
| Some c -> c
| Some c -> c
| None -> Apply ( f , es ) )
| None -> Apply ( f , es ) )
| > check invariant
| > check invariant
(* * Traverse *)
let rec iter_vars e ~ f =
match e with
| Var _ as v -> f ( Var1 . of_ v )
| Z _ | Q _ -> ()
| Splat x -> iter_vars ~ f x
| Sized { seq = x ; siz = y } ->
iter_vars ~ f x ;
iter_vars ~ f y
| Extract { seq = x ; off = y ; len = z } ->
iter_vars ~ f x ;
iter_vars ~ f y ;
iter_vars ~ f z
| Concat xs | Apply ( _ , xs ) -> Array . iter ~ f : ( iter_vars ~ f ) xs
| Arith a -> Iter . iter ~ f : ( iter_vars ~ f ) ( Arith . trms a )
let vars e = Iter . from_labelled_iter ( iter_vars e )
end
include Trm
module Var = Var1
module Set = struct
include Set . Make ( Trm )
include Provide_of_sexp ( Trm )
include Provide_pp ( Trm )
let of_vars : Var . Set . t -> t =
fun vs ->
of_iter
( Iter . map ~ f : ( fun v -> ( v : Var . t :> Trm . t ) ) ( Var . Set . to_iter vs ) )
end
module Map = struct
include Map . Make ( Trm )
include Provide_of_sexp ( Trm )
end
type arith = Arith . t
let pp_diff fs ( x , y ) = Format . fprintf fs " -- %a ++ %a " pp x pp y
(* * Construct *)
(* variables *)
let var v = ( v : Var . t :> t )
(* arithmetic *)
let zero = _ Z Z . zero
let one = _ Z Z . one
let integer z = _ Z z
let rational q = _ Q q
let neg x = _ Arith Arith . ( neg ( trm x ) )
let add = Trm . add
let sub = Trm . sub
let mulq q x = _ Arith Arith . ( mulc q ( trm x ) )
let mul x y = _ Arith ( Arith . mul x y )
let div x y = _ Arith ( Arith . div x y )
let pow x i = _ Arith ( Arith . pow x i )
let arith = _ Arith
(* sequences *)
let splat = _ Splat
let sized = _ Sized
let extract = _ Extract
let concat elts = _ Concat elts
(* uninterpreted *)
let apply sym args = _ Apply sym args
(* * Traverse *)
(* * Traverse *)
let trms = function
let trms = function
@ -505,25 +443,25 @@ let rec map_vars e ~f =
| Var _ as v -> ( f ( Var . of_ v ) : Var . t :> t )
| Var _ as v -> ( f ( Var . of_ v ) : Var . t :> t )
| Z _ | Q _ -> e
| Z _ | Q _ -> e
| Arith a -> map1 ( Arith . map ~ f : ( map_vars ~ f ) ) e _ Arith a
| Arith a -> map1 ( Arith . map ~ f : ( map_vars ~ f ) ) e _ Arith a
| Splat x -> map1 ( map_vars ~ f ) e _ S plat x
| Splat x -> map1 ( map_vars ~ f ) e s plat x
| Sized { seq ; siz } ->
| Sized { seq ; siz } ->
map2 ( map_vars ~ f ) e ( fun seq siz -> _ S ized ~ seq ~ siz ) seq siz
map2 ( map_vars ~ f ) e ( fun seq siz -> s ized ~ seq ~ siz ) seq siz
| Extract { seq ; off ; len } ->
| Extract { seq ; off ; len } ->
map3 ( map_vars ~ f ) e
map3 ( map_vars ~ f ) e
( fun seq off len -> _ E xtract ~ seq ~ off ~ len )
( fun seq off len -> e xtract ~ seq ~ off ~ len )
seq off len
seq off len
| Concat xs -> mapN ( map_vars ~ f ) e _ C oncat xs
| Concat xs -> mapN ( map_vars ~ f ) e c oncat xs
| Apply ( g , xs ) -> mapN ( map_vars ~ f ) e ( _ A pply g ) xs
| Apply ( g , xs ) -> mapN ( map_vars ~ f ) e ( a pply g ) xs
let map e ~ f =
let map e ~ f =
match e with
match e with
| Var _ | Z _ | Q _ -> e
| Var _ | Z _ | Q _ -> e
| Arith a -> map1 ( Arith . map ~ f ) e _ Arith a
| Arith a -> map1 ( Arith . map ~ f ) e _ Arith a
| Splat x -> map1 f e _ S plat x
| Splat x -> map1 f e s plat x
| Sized { seq ; siz } -> map2 f e ( fun seq siz -> _ S ized ~ seq ~ siz ) seq siz
| Sized { seq ; siz } -> map2 f e ( fun seq siz -> s ized ~ seq ~ siz ) seq siz
| Extract { seq ; off ; len } ->
| Extract { seq ; off ; len } ->
map3 f e ( fun seq off len -> _ E xtract ~ seq ~ off ~ len ) seq off len
map3 f e ( fun seq off len -> e xtract ~ seq ~ off ~ len ) seq off len
| Concat xs -> mapN f e _ C oncat xs
| Concat xs -> mapN f e c oncat xs
| Apply ( g , xs ) -> mapN f e ( _ A pply g ) xs
| Apply ( g , xs ) -> mapN f e ( a pply g ) xs
let fold_map e = fold_map_from_map map e
let fold_map e = fold_map_from_map map e