├── .gitignore ├── CHANGES.md ├── META ├── Makefile ├── README.md ├── _oasis ├── _tags ├── configure ├── lens.ml ├── lens.mldylib ├── lens.mli ├── lens.mllib ├── myocamlbuild.ml ├── opam └── lens.1.0.0 │ ├── descr │ ├── findlib │ ├── opam │ └── url └── setup.ml /.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | setup.log 3 | setup.data 4 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | 1.0.0 (30-Mar-2015): 2 | * Initial public release. 3 | -------------------------------------------------------------------------------- /META: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 7110d18b69c7e1be3e06de9015a49fe6) 3 | version = "1.0.0" 4 | description = "Functional lenses" 5 | archive(byte) = "lens.cma" 6 | archive(byte, plugin) = "lens.cma" 7 | archive(native) = "lens.cmxa" 8 | archive(native, plugin) = "lens.cmxs" 9 | exists_if = "lens.cma" 10 | # OASIS_STOP 11 | 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: a3c674b4239234cbbe53afe090018954) 3 | 4 | SETUP = ocaml setup.ml 5 | 6 | build: setup.data 7 | $(SETUP) -build $(BUILDFLAGS) 8 | 9 | doc: setup.data build 10 | $(SETUP) -doc $(DOCFLAGS) 11 | 12 | test: setup.data build 13 | $(SETUP) -test $(TESTFLAGS) 14 | 15 | all: 16 | $(SETUP) -all $(ALLFLAGS) 17 | 18 | install: setup.data 19 | $(SETUP) -install $(INSTALLFLAGS) 20 | 21 | uninstall: setup.data 22 | $(SETUP) -uninstall $(UNINSTALLFLAGS) 23 | 24 | reinstall: setup.data 25 | $(SETUP) -reinstall $(REINSTALLFLAGS) 26 | 27 | clean: 28 | $(SETUP) -clean $(CLEANFLAGS) 29 | 30 | distclean: 31 | $(SETUP) -distclean $(DISTCLEANFLAGS) 32 | 33 | setup.data: 34 | $(SETUP) -configure $(CONFIGUREFLAGS) 35 | 36 | configure: 37 | $(SETUP) -configure $(CONFIGUREFLAGS) 38 | 39 | .PHONY: build doc test all install uninstall reinstall clean distclean configure 40 | 41 | # OASIS_STOP 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Functional Lenses 2 | ================= 3 | 4 | This package provides some basic types and functions for using lenses in OCaml. 5 | Functional lenses are based on F# implementation in [FSharpX](https://github.com/fsharp/fsharpx). See [src/FSharpx.Core/Lens.fs](https://github.com/fsharp/fsharpx/blob/master/src/FSharpx.Core/Lens.fs) for the original implementation. Written by Alessandro Strada. 6 | 7 | See also: 8 | * Lenses in F# 9 | * Stackoverflow question about Updating nested immutable data structures 10 | * Haskell libraries for structure access and mutation 11 | * Functional lenses for Scala by Edward Kmett on YouTube 12 | * Lenses are the coalgebras for the costate comonad by Jeremy Gibbons 13 | 14 | Examples 15 | ======== 16 | 17 | First load `Lens` in utop. 18 | 19 | utop # #use "lens.ml";; 20 | 21 | Given a couple of records 22 | 23 | type car = { 24 | make : string; 25 | model: string; 26 | mileage: int; 27 | };; 28 | 29 | type editor = { 30 | name: string; 31 | salary: int; 32 | car: car; 33 | };; 34 | 35 | type book = { 36 | name: string; 37 | author: string; 38 | editor: editor; 39 | };; 40 | 41 | Create a new nested record 42 | 43 | let scifi_novel = { 44 | name = "Metro 2033"; 45 | author = "Dmitry Glukhovsky"; 46 | editor = { 47 | name = "Vitali Gubarev"; 48 | salary = 1300; 49 | car = { 50 | make = "Lada"; 51 | model = "VAZ-2103"; 52 | mileage = 310000 53 | } 54 | } 55 | };; 56 | 57 | Now to construct a few lenses to access some things 58 | 59 | let car_lens = { 60 | get = (fun x -> x.car); 61 | set = (fun v x -> { x with car = v }) 62 | };; 63 | 64 | let editor_lens = { 65 | get = (fun x -> x.editor); 66 | set = (fun v x -> { x with editor = v }) 67 | };; 68 | 69 | let mileage_lens = { 70 | get = (fun x -> x.mileage); 71 | set = (fun v x -> { x with mileage = v }) 72 | 73 | };; 74 | 75 | Using these lenses we can modify the mileage without having to unpack the record 76 | 77 | let a = compose mileage_lens (compose car_lens editor_lens) in 78 | _set 10 scifi_novel a;; 79 | 80 | Or using the `Infix` module we can do the same thing, only shorter. 81 | 82 | _set 10 scifi_novel (editor_lens |-- car_lens |-- mileage_lens);; 83 | 84 | (* or *) 85 | 86 | ((editor_lens |-- car_lens |-- mileage_lens) ^= 10) @@ scifi_novel;; 87 | -------------------------------------------------------------------------------- /_oasis: -------------------------------------------------------------------------------- 1 | OASISFormat: 0.4 2 | Name: lens 3 | Description: 4 | Based on F# implementation in https://github.com/fsharp/fsharpx 5 | see https://github.com/fsharp/fsharpx/blob/master/src/FSharpx.Core/Lens.fs for the original implementation 6 | 7 | see http://bugsquash.blogspot.com/2011/11/lenses-in-f.html - Lenses in F# 8 | see http://stackoverflow.com/questions/8179485/updating-nested-immutable-data-structures - Stackoverflow question about Updating nested immutable data structures 9 | see http://stackoverflow.com/questions/5767129/lenses-fclabels-data-accessor-which-library-for-structure-access-and-mutatio - Haskell libraries for structure access and mutation 10 | see http://www.youtube.com/watch?v=efv0SQNde5Q - Functional lenses for Scala by Edward Kmett on YouTube 11 | see http://patternsinfp.wordpress.com/2011/01/31/lenses-are-the-coalgebras-for-the-costate-comonad - Lenses are the coalgebras for the costate comonad by Jeremy Gibbons 12 | Homepage: https://github.com/avsm/ocaml-lens 13 | Version: 1.0.0 14 | Synopsis: Functional lenses 15 | Authors: Alessandro Strada 16 | Maintainers: Paolo Donadeo 17 | License: BSD-3-clause 18 | Plugins: META (0.4), DevFiles (0.4) 19 | BuildTools: ocamlbuild 20 | 21 | Library lens 22 | Path: . 23 | Findlibname: lens 24 | Modules: Lens 25 | -------------------------------------------------------------------------------- /_tags: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 817ce6a3a9d69331ede00a1f71851b59) 3 | # Ignore VCS directories, you can use the same kind of rule outside 4 | # OASIS_START/STOP if you want to exclude directories that contains 5 | # useless stuff for the build process 6 | true: annot, bin_annot 7 | <**/.svn>: -traverse 8 | <**/.svn>: not_hygienic 9 | ".bzr": -traverse 10 | ".bzr": not_hygienic 11 | ".hg": -traverse 12 | ".hg": not_hygienic 13 | ".git": -traverse 14 | ".git": not_hygienic 15 | "_darcs": -traverse 16 | "_darcs": not_hygienic 17 | # Library lens 18 | "lens.cmxs": use_lens 19 | # OASIS_STOP 20 | true: debug, principal 21 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # OASIS_START 4 | # DO NOT EDIT (digest: dc86c2ad450f91ca10c931b6045d0499) 5 | set -e 6 | 7 | FST=true 8 | for i in "$@"; do 9 | if $FST; then 10 | set -- 11 | FST=false 12 | fi 13 | 14 | case $i in 15 | --*=*) 16 | ARG=${i%%=*} 17 | VAL=${i##*=} 18 | set -- "$@" "$ARG" "$VAL" 19 | ;; 20 | *) 21 | set -- "$@" "$i" 22 | ;; 23 | esac 24 | done 25 | 26 | ocaml setup.ml -configure "$@" 27 | # OASIS_STOP 28 | -------------------------------------------------------------------------------- /lens.ml: -------------------------------------------------------------------------------- 1 | (* 2 | Copyright (c) 2011-2012 Alessandro Strada 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | *) 22 | 23 | let (|-) f g x = g (f x) 24 | 25 | type ('a, 'b) t = { 26 | get : 'a -> 'b; 27 | set : 'b -> 'a -> 'a 28 | } 29 | 30 | let modify l f a = 31 | let value = l.get a in 32 | let new_value = f value in 33 | l.set new_value a 34 | 35 | let _get a l = l.get a 36 | 37 | let _set v a l = l.set v a 38 | 39 | let _modify f l = modify l f 40 | 41 | let compose l1 l2 = { 42 | get = l2.get |- l1.get; 43 | set = l1.set |- modify l2 44 | } 45 | 46 | let pair l1 l2 = { 47 | get = (fun (a, b) -> (l1.get a, l2.get b)); 48 | set = (fun (a, c) (b, d) -> (l1.set a b, l2.set c d)) 49 | } 50 | 51 | let pair3 l1 l2 l3 = { 52 | get = (fun (a, b, c) -> (l1.get a, l2.get b, l3.get c)); 53 | set = (fun (a, c, e) (b, d, f) -> (l1.set a b, l2.set c d, l3.set e f)) 54 | } 55 | 56 | let cond pred lt lf = 57 | let choose a = if pred a then lt else lf in 58 | { get = (fun a -> choose a |> _get a); 59 | set = (fun b a -> choose a |> _set b a) 60 | } 61 | 62 | let get_state l = 63 | fun a -> _get a l, a 64 | 65 | let put_state l v = 66 | fun a -> (), _set v a l 67 | 68 | let modify_state l f = 69 | fun a -> (), _modify f l a 70 | 71 | let ignore = { 72 | get = ignore; 73 | set = (fun _ a -> a) 74 | } 75 | 76 | let id = { 77 | get = (fun a -> a); 78 | set = (fun b a -> b) 79 | } 80 | 81 | let first = { 82 | get = fst; 83 | set = (fun v a -> v, snd a) 84 | } 85 | 86 | let second = { 87 | get = snd; 88 | set = (fun v a -> fst a, v) 89 | } 90 | 91 | let head = { 92 | get = List.hd; 93 | set = (fun v xs -> v :: List.tl xs) 94 | } 95 | 96 | let tail = { 97 | get = List.tl; 98 | set = (fun v xs -> List.hd xs :: v) 99 | } 100 | 101 | let for_hash key = { 102 | get = (fun h -> 103 | try 104 | Some (Hashtbl.find h key) 105 | with Not_found -> None); 106 | set = (fun v h -> 107 | match v with 108 | Some value -> Hashtbl.add h key value; h 109 | | None -> Hashtbl.remove h key; h) 110 | } 111 | 112 | let for_assoc key = { 113 | get = (fun l -> 114 | try 115 | Some (List.assoc key l) 116 | with Not_found -> None); 117 | set = (fun v l -> 118 | match v with 119 | Some value -> 120 | let l' = List.remove_assoc key l in 121 | (key, value) :: l' 122 | | None -> List.remove_assoc key l) 123 | } 124 | 125 | let for_array i = { 126 | get = (fun a -> Array.get a i); 127 | set = (fun v a -> let a' = Array.copy a in Array.set a' i v; a') 128 | } 129 | 130 | let for_list i = { 131 | get = (fun xs -> List.nth xs i); 132 | set = (fun v xs -> 133 | List.fold_left 134 | (fun (xs', j) x -> 135 | (if i = j then v::xs' else x::xs'), (j+1)) 136 | ([], 0) 137 | xs |> fst |> List.rev) 138 | } 139 | 140 | let option_get = { 141 | get = (function None -> raise Not_found | Some v -> v); 142 | set = (fun v _ -> Some v) 143 | } 144 | 145 | let list_map l = { 146 | get = List.map l.get; 147 | set = List.map2 l.set 148 | } 149 | 150 | (* TODO: array_map *) 151 | 152 | let xmap f g l = { 153 | get = l.get |- f; 154 | set = g |- l.set 155 | } 156 | 157 | module Infix = 158 | struct 159 | let (|.) = _get 160 | 161 | let (^=) l v = fun a -> _set v a l 162 | 163 | let (^%=) = modify 164 | 165 | let (|--) l1 l2 = compose l2 l1 166 | 167 | let (--|) = compose 168 | 169 | let ( *** ) l1 l2 = pair l1 l2 170 | 171 | let (+=) l v = _modify ((+) v) l 172 | 173 | let (-=) l v = _modify ((-) v) l 174 | 175 | end 176 | 177 | module StateInfix = 178 | struct 179 | let (^=!) l v = put_state l v 180 | 181 | let (+=!) l v = modify_state l ((+) v) 182 | 183 | let (-=!) l v = modify_state l ((-) v) 184 | 185 | let (@=!) l v = modify_state l (fun a -> a @ v) 186 | 187 | end 188 | 189 | -------------------------------------------------------------------------------- /lens.mldylib: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 443b8e6205a0c76a3e6a2eed788215e0) 3 | Lens 4 | # OASIS_STOP 5 | -------------------------------------------------------------------------------- /lens.mli: -------------------------------------------------------------------------------- 1 | (* 2 | Copyright (c) 2011-2012 Alessandro Strada 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | *) 22 | 23 | (** Functional lenses. 24 | 25 | Based on F# implementation in {{:https://github.com/fsharp/fsharpx}FSharpx} 26 | (see {{:https://github.com/fsharp/fsharpx/blob/master/src/FSharpx.Core/Lens.fs}src/FSharpx.Core/Lens.fs} for the original implementation) 27 | 28 | @see Lenses in F# 29 | @see Stackoverflow question about Updating nested immutable data structures 30 | @see Haskell libraries for structure access and mutation 31 | @see Functional lenses for Scala by Edward Kmett on YouTube 32 | @see Lenses are the coalgebras for the costate comonad by Jeremy Gibbons 33 | *) 34 | 35 | (** Lens type definition *) 36 | type ('a, 'b) t = { 37 | get : 'a -> 'b; 38 | (** Functional getter *) 39 | set : 'b -> 'a -> 'a 40 | (** Functional setter *) 41 | } 42 | 43 | (** Updates a value through a lens *) 44 | val modify : ('a, 'b) t -> ('b -> 'b) -> 'a -> 'a 45 | 46 | (** {3 Combinators} *) 47 | 48 | (** Sequentially composes two lenses *) 49 | val compose : ('a, 'b) t -> ('c, 'a) t -> ('c, 'b) t 50 | 51 | (** Pairs two lenses *) 52 | val pair : ('a, 'b) t -> ('c, 'd) t -> ('a * 'c, 'b * 'd) t 53 | 54 | (** Pairs three lenses *) 55 | val pair3 : ('a, 'b) t -> ('c, 'd) t -> ('e, 'f) t -> ('a * 'c * 'e, 'b * 'd * 'f) t 56 | 57 | (** Selects a lens checking a predicate. 58 | 59 | [cond pred lensTrue lensFalse]: [pred] is applied to source. If [true], [lensTrue] is selected. If [false], [lensFalse] is selected. *) 60 | val cond : ('a -> bool) -> ('a, 'b) t -> ('a, 'b) t -> ('a, 'b) t 61 | 62 | (** {3 State monad integration} *) 63 | 64 | (** Gets a value from the state monad. *) 65 | val get_state : ('a, 'b) t -> 'a -> 'b * 'a 66 | 67 | (** Puts a value in the state monad. *) 68 | val put_state : ('a, 'b) t -> 'b -> 'a -> unit * 'a 69 | 70 | (** Modifies a value in the state monad. *) 71 | val modify_state : ('a, 'b) t -> ('b -> 'b) -> 'a -> unit * 'a 72 | 73 | (** {3 Stock lenses} *) 74 | 75 | (** Trivial lens *) 76 | val ignore : ('a, unit) t 77 | 78 | (** Identity lens *) 79 | val id : ('a, 'a) t 80 | 81 | (** Gets/sets the first element in a pair *) 82 | val first : ('a * 'b, 'a) t 83 | 84 | (** Gets/sets the second element in a pair *) 85 | val second : ('a * 'b, 'b) t 86 | 87 | (** Gets/sets the first element in a list *) 88 | val head : ('a list, 'a) t 89 | 90 | (** Gets/sets the tail of a list *) 91 | val tail : ('a list, 'a list) t 92 | 93 | (** Lens for a particular key in a hashtable *) 94 | val for_hash : 'a -> (('a, 'b) Hashtbl.t, 'b option) t 95 | 96 | (** Lens for a particular key in an associative list *) 97 | val for_assoc : 'a -> (('a * 'b) list, 'b option) t 98 | 99 | (** Lens for a particular position in an array *) 100 | val for_array : int -> ('a array, 'a) t 101 | 102 | (** Lens for a particular position in a list *) 103 | val for_list : int -> ('a list, 'a) t 104 | 105 | (** Lens for extracting the value from an option type (same as Option.get) *) 106 | val option_get : ('a option, 'a) t 107 | 108 | (** {3 List combinators} *) 109 | 110 | (** Creates a lens that maps the given lens in a list *) 111 | val list_map : ('a, 'b) t -> ('a list, 'b list) t 112 | 113 | (** {3 Isomorphism} *) 114 | 115 | (** Applies an isomorphism to the value viewed through a lens *) 116 | val xmap : ('a -> 'b) -> ('b -> 'a) -> ('c, 'a) t -> ('c, 'b) t 117 | 118 | (** Infix operators *) 119 | module Infix : 120 | sig 121 | val ( |. ) : 'a -> ('a, 'b) t -> 'b 122 | (** Get operator *) 123 | 124 | val ( ^= ) : ('a, 'b) t -> 'b -> 'a -> 'a 125 | (** Set operator *) 126 | 127 | val ( ^%= ) : ('a, 'b) t -> ('b -> 'b) -> 'a -> 'a 128 | (** Mod operator *) 129 | 130 | (** {3 Composition} *) 131 | 132 | val ( |-- ) : ('a, 'b) t -> ('b, 'c) t -> ('a, 'c) t 133 | (** Flipped compose operator *) 134 | 135 | val ( --| ) : ('a, 'b) t -> ('c, 'a) t -> ('c, 'b) t 136 | (** Compose operator *) 137 | 138 | val ( *** ) : ('a, 'b) t -> ('c, 'd) t -> ('a * 'c, 'b * 'd) t 139 | (** Pair operator *) 140 | 141 | (** {3 Pseudo-imperatives} *) 142 | 143 | val ( += ) : ('a, int) t -> int -> 'a -> 'a 144 | 145 | val ( -= ) : ('a, int) t -> int -> 'a -> 'a 146 | 147 | end 148 | 149 | (** Infix operators for the state monad *) 150 | module StateInfix : 151 | sig 152 | val ( ^=! ) : ('a, 'b) t -> 'b -> 'a -> unit * 'a 153 | (** Set operator *) 154 | 155 | (** {3 Pseudo-imperatives} *) 156 | 157 | val ( +=! ) : ('a, int) t -> int -> 'a -> unit * 'a 158 | 159 | val ( -=! ) : ('a, int) t -> int -> 'a -> unit * 'a 160 | 161 | val ( @=! ) : ('a, 'b list) t -> 'b list -> 'a -> unit * 'a 162 | end 163 | -------------------------------------------------------------------------------- /lens.mllib: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 443b8e6205a0c76a3e6a2eed788215e0) 3 | Lens 4 | # OASIS_STOP 5 | -------------------------------------------------------------------------------- /myocamlbuild.ml: -------------------------------------------------------------------------------- 1 | (* OASIS_START *) 2 | (* DO NOT EDIT (digest: 2ee1b65797d78eba0e238e3eeb0c20c5) *) 3 | module OASISGettext = struct 4 | (* # 22 "src/oasis/OASISGettext.ml" *) 5 | 6 | 7 | let ns_ str = 8 | str 9 | 10 | 11 | let s_ str = 12 | str 13 | 14 | 15 | let f_ (str: ('a, 'b, 'c, 'd) format4) = 16 | str 17 | 18 | 19 | let fn_ fmt1 fmt2 n = 20 | if n = 1 then 21 | fmt1^^"" 22 | else 23 | fmt2^^"" 24 | 25 | 26 | let init = 27 | [] 28 | 29 | 30 | end 31 | 32 | module OASISExpr = struct 33 | (* # 22 "src/oasis/OASISExpr.ml" *) 34 | 35 | 36 | 37 | 38 | 39 | open OASISGettext 40 | 41 | 42 | type test = string 43 | 44 | 45 | type flag = string 46 | 47 | 48 | type t = 49 | | EBool of bool 50 | | ENot of t 51 | | EAnd of t * t 52 | | EOr of t * t 53 | | EFlag of flag 54 | | ETest of test * string 55 | 56 | 57 | 58 | type 'a choices = (t * 'a) list 59 | 60 | 61 | let eval var_get t = 62 | let rec eval' = 63 | function 64 | | EBool b -> 65 | b 66 | 67 | | ENot e -> 68 | not (eval' e) 69 | 70 | | EAnd (e1, e2) -> 71 | (eval' e1) && (eval' e2) 72 | 73 | | EOr (e1, e2) -> 74 | (eval' e1) || (eval' e2) 75 | 76 | | EFlag nm -> 77 | let v = 78 | var_get nm 79 | in 80 | assert(v = "true" || v = "false"); 81 | (v = "true") 82 | 83 | | ETest (nm, vl) -> 84 | let v = 85 | var_get nm 86 | in 87 | (v = vl) 88 | in 89 | eval' t 90 | 91 | 92 | let choose ?printer ?name var_get lst = 93 | let rec choose_aux = 94 | function 95 | | (cond, vl) :: tl -> 96 | if eval var_get cond then 97 | vl 98 | else 99 | choose_aux tl 100 | | [] -> 101 | let str_lst = 102 | if lst = [] then 103 | s_ "" 104 | else 105 | String.concat 106 | (s_ ", ") 107 | (List.map 108 | (fun (cond, vl) -> 109 | match printer with 110 | | Some p -> p vl 111 | | None -> s_ "") 112 | lst) 113 | in 114 | match name with 115 | | Some nm -> 116 | failwith 117 | (Printf.sprintf 118 | (f_ "No result for the choice list '%s': %s") 119 | nm str_lst) 120 | | None -> 121 | failwith 122 | (Printf.sprintf 123 | (f_ "No result for a choice list: %s") 124 | str_lst) 125 | in 126 | choose_aux (List.rev lst) 127 | 128 | 129 | end 130 | 131 | 132 | # 132 "myocamlbuild.ml" 133 | module BaseEnvLight = struct 134 | (* # 22 "src/base/BaseEnvLight.ml" *) 135 | 136 | 137 | module MapString = Map.Make(String) 138 | 139 | 140 | type t = string MapString.t 141 | 142 | 143 | let default_filename = 144 | Filename.concat 145 | (Sys.getcwd ()) 146 | "setup.data" 147 | 148 | 149 | let load ?(allow_empty=false) ?(filename=default_filename) () = 150 | if Sys.file_exists filename then 151 | begin 152 | let chn = 153 | open_in_bin filename 154 | in 155 | let st = 156 | Stream.of_channel chn 157 | in 158 | let line = 159 | ref 1 160 | in 161 | let st_line = 162 | Stream.from 163 | (fun _ -> 164 | try 165 | match Stream.next st with 166 | | '\n' -> incr line; Some '\n' 167 | | c -> Some c 168 | with Stream.Failure -> None) 169 | in 170 | let lexer = 171 | Genlex.make_lexer ["="] st_line 172 | in 173 | let rec read_file mp = 174 | match Stream.npeek 3 lexer with 175 | | [Genlex.Ident nm; Genlex.Kwd "="; Genlex.String value] -> 176 | Stream.junk lexer; 177 | Stream.junk lexer; 178 | Stream.junk lexer; 179 | read_file (MapString.add nm value mp) 180 | | [] -> 181 | mp 182 | | _ -> 183 | failwith 184 | (Printf.sprintf 185 | "Malformed data file '%s' line %d" 186 | filename !line) 187 | in 188 | let mp = 189 | read_file MapString.empty 190 | in 191 | close_in chn; 192 | mp 193 | end 194 | else if allow_empty then 195 | begin 196 | MapString.empty 197 | end 198 | else 199 | begin 200 | failwith 201 | (Printf.sprintf 202 | "Unable to load environment, the file '%s' doesn't exist." 203 | filename) 204 | end 205 | 206 | 207 | let rec var_expand str env = 208 | let buff = 209 | Buffer.create ((String.length str) * 2) 210 | in 211 | Buffer.add_substitute 212 | buff 213 | (fun var -> 214 | try 215 | var_expand (MapString.find var env) env 216 | with Not_found -> 217 | failwith 218 | (Printf.sprintf 219 | "No variable %s defined when trying to expand %S." 220 | var 221 | str)) 222 | str; 223 | Buffer.contents buff 224 | 225 | 226 | let var_get name env = 227 | var_expand (MapString.find name env) env 228 | 229 | 230 | let var_choose lst env = 231 | OASISExpr.choose 232 | (fun nm -> var_get nm env) 233 | lst 234 | end 235 | 236 | 237 | # 237 "myocamlbuild.ml" 238 | module MyOCamlbuildFindlib = struct 239 | (* # 22 "src/plugins/ocamlbuild/MyOCamlbuildFindlib.ml" *) 240 | 241 | 242 | (** OCamlbuild extension, copied from 243 | * http://brion.inria.fr/gallium/index.php/Using_ocamlfind_with_ocamlbuild 244 | * by N. Pouillard and others 245 | * 246 | * Updated on 2009/02/28 247 | * 248 | * Modified by Sylvain Le Gall 249 | *) 250 | open Ocamlbuild_plugin 251 | 252 | type conf = 253 | { no_automatic_syntax: bool; 254 | } 255 | 256 | (* these functions are not really officially exported *) 257 | let run_and_read = 258 | Ocamlbuild_pack.My_unix.run_and_read 259 | 260 | 261 | let blank_sep_strings = 262 | Ocamlbuild_pack.Lexers.blank_sep_strings 263 | 264 | 265 | let exec_from_conf exec = 266 | let exec = 267 | let env_filename = Pathname.basename BaseEnvLight.default_filename in 268 | let env = BaseEnvLight.load ~filename:env_filename ~allow_empty:true () in 269 | try 270 | BaseEnvLight.var_get exec env 271 | with Not_found -> 272 | Printf.eprintf "W: Cannot get variable %s\n" exec; 273 | exec 274 | in 275 | let fix_win32 str = 276 | if Sys.os_type = "Win32" then begin 277 | let buff = Buffer.create (String.length str) in 278 | (* Adapt for windowsi, ocamlbuild + win32 has a hard time to handle '\\'. 279 | *) 280 | String.iter 281 | (fun c -> Buffer.add_char buff (if c = '\\' then '/' else c)) 282 | str; 283 | Buffer.contents buff 284 | end else begin 285 | str 286 | end 287 | in 288 | fix_win32 exec 289 | 290 | let split s ch = 291 | let buf = Buffer.create 13 in 292 | let x = ref [] in 293 | let flush () = 294 | x := (Buffer.contents buf) :: !x; 295 | Buffer.clear buf 296 | in 297 | String.iter 298 | (fun c -> 299 | if c = ch then 300 | flush () 301 | else 302 | Buffer.add_char buf c) 303 | s; 304 | flush (); 305 | List.rev !x 306 | 307 | 308 | let split_nl s = split s '\n' 309 | 310 | 311 | let before_space s = 312 | try 313 | String.before s (String.index s ' ') 314 | with Not_found -> s 315 | 316 | (* ocamlfind command *) 317 | let ocamlfind x = S[Sh (exec_from_conf "ocamlfind"); x] 318 | 319 | (* This lists all supported packages. *) 320 | let find_packages () = 321 | List.map before_space (split_nl & run_and_read (exec_from_conf "ocamlfind" ^ " list")) 322 | 323 | 324 | (* Mock to list available syntaxes. *) 325 | let find_syntaxes () = ["camlp4o"; "camlp4r"] 326 | 327 | 328 | let well_known_syntax = [ 329 | "camlp4.quotations.o"; 330 | "camlp4.quotations.r"; 331 | "camlp4.exceptiontracer"; 332 | "camlp4.extend"; 333 | "camlp4.foldgenerator"; 334 | "camlp4.listcomprehension"; 335 | "camlp4.locationstripper"; 336 | "camlp4.macro"; 337 | "camlp4.mapgenerator"; 338 | "camlp4.metagenerator"; 339 | "camlp4.profiler"; 340 | "camlp4.tracer" 341 | ] 342 | 343 | 344 | let dispatch conf = 345 | function 346 | | After_options -> 347 | (* By using Before_options one let command line options have an higher 348 | * priority on the contrary using After_options will guarantee to have 349 | * the higher priority override default commands by ocamlfind ones *) 350 | Options.ocamlc := ocamlfind & A"ocamlc"; 351 | Options.ocamlopt := ocamlfind & A"ocamlopt"; 352 | Options.ocamldep := ocamlfind & A"ocamldep"; 353 | Options.ocamldoc := ocamlfind & A"ocamldoc"; 354 | Options.ocamlmktop := ocamlfind & A"ocamlmktop"; 355 | Options.ocamlmklib := ocamlfind & A"ocamlmklib" 356 | 357 | | After_rules -> 358 | 359 | (* When one link an OCaml library/binary/package, one should use 360 | * -linkpkg *) 361 | flag ["ocaml"; "link"; "program"] & A"-linkpkg"; 362 | 363 | if not (conf.no_automatic_syntax) then begin 364 | (* For each ocamlfind package one inject the -package option when 365 | * compiling, computing dependencies, generating documentation and 366 | * linking. *) 367 | List.iter 368 | begin fun pkg -> 369 | let base_args = [A"-package"; A pkg] in 370 | (* TODO: consider how to really choose camlp4o or camlp4r. *) 371 | let syn_args = [A"-syntax"; A "camlp4o"] in 372 | let (args, pargs) = 373 | (* Heuristic to identify syntax extensions: whether they end in 374 | ".syntax"; some might not. 375 | *) 376 | if Filename.check_suffix pkg "syntax" || 377 | List.mem pkg well_known_syntax then 378 | (syn_args @ base_args, syn_args) 379 | else 380 | (base_args, []) 381 | in 382 | flag ["ocaml"; "compile"; "pkg_"^pkg] & S args; 383 | flag ["ocaml"; "ocamldep"; "pkg_"^pkg] & S args; 384 | flag ["ocaml"; "doc"; "pkg_"^pkg] & S args; 385 | flag ["ocaml"; "link"; "pkg_"^pkg] & S base_args; 386 | flag ["ocaml"; "infer_interface"; "pkg_"^pkg] & S args; 387 | 388 | (* TODO: Check if this is allowed for OCaml < 3.12.1 *) 389 | flag ["ocaml"; "compile"; "package("^pkg^")"] & S pargs; 390 | flag ["ocaml"; "ocamldep"; "package("^pkg^")"] & S pargs; 391 | flag ["ocaml"; "doc"; "package("^pkg^")"] & S pargs; 392 | flag ["ocaml"; "infer_interface"; "package("^pkg^")"] & S pargs; 393 | end 394 | (find_packages ()); 395 | end; 396 | 397 | (* Like -package but for extensions syntax. Morover -syntax is useless 398 | * when linking. *) 399 | List.iter begin fun syntax -> 400 | flag ["ocaml"; "compile"; "syntax_"^syntax] & S[A"-syntax"; A syntax]; 401 | flag ["ocaml"; "ocamldep"; "syntax_"^syntax] & S[A"-syntax"; A syntax]; 402 | flag ["ocaml"; "doc"; "syntax_"^syntax] & S[A"-syntax"; A syntax]; 403 | flag ["ocaml"; "infer_interface"; "syntax_"^syntax] & 404 | S[A"-syntax"; A syntax]; 405 | end (find_syntaxes ()); 406 | 407 | (* The default "thread" tag is not compatible with ocamlfind. 408 | * Indeed, the default rules add the "threads.cma" or "threads.cmxa" 409 | * options when using this tag. When using the "-linkpkg" option with 410 | * ocamlfind, this module will then be added twice on the command line. 411 | * 412 | * To solve this, one approach is to add the "-thread" option when using 413 | * the "threads" package using the previous plugin. 414 | *) 415 | flag ["ocaml"; "pkg_threads"; "compile"] (S[A "-thread"]); 416 | flag ["ocaml"; "pkg_threads"; "doc"] (S[A "-I"; A "+threads"]); 417 | flag ["ocaml"; "pkg_threads"; "link"] (S[A "-thread"]); 418 | flag ["ocaml"; "pkg_threads"; "infer_interface"] (S[A "-thread"]); 419 | flag ["ocaml"; "package(threads)"; "compile"] (S[A "-thread"]); 420 | flag ["ocaml"; "package(threads)"; "doc"] (S[A "-I"; A "+threads"]); 421 | flag ["ocaml"; "package(threads)"; "link"] (S[A "-thread"]); 422 | flag ["ocaml"; "package(threads)"; "infer_interface"] (S[A "-thread"]); 423 | 424 | | _ -> 425 | () 426 | end 427 | 428 | module MyOCamlbuildBase = struct 429 | (* # 22 "src/plugins/ocamlbuild/MyOCamlbuildBase.ml" *) 430 | 431 | 432 | (** Base functions for writing myocamlbuild.ml 433 | @author Sylvain Le Gall 434 | *) 435 | 436 | 437 | 438 | 439 | 440 | open Ocamlbuild_plugin 441 | module OC = Ocamlbuild_pack.Ocaml_compiler 442 | 443 | 444 | type dir = string 445 | type file = string 446 | type name = string 447 | type tag = string 448 | 449 | 450 | (* # 62 "src/plugins/ocamlbuild/MyOCamlbuildBase.ml" *) 451 | 452 | 453 | type t = 454 | { 455 | lib_ocaml: (name * dir list * string list) list; 456 | lib_c: (name * dir * file list) list; 457 | flags: (tag list * (spec OASISExpr.choices)) list; 458 | (* Replace the 'dir: include' from _tags by a precise interdepends in 459 | * directory. 460 | *) 461 | includes: (dir * dir list) list; 462 | } 463 | 464 | 465 | let env_filename = 466 | Pathname.basename 467 | BaseEnvLight.default_filename 468 | 469 | 470 | let dispatch_combine lst = 471 | fun e -> 472 | List.iter 473 | (fun dispatch -> dispatch e) 474 | lst 475 | 476 | 477 | let tag_libstubs nm = 478 | "use_lib"^nm^"_stubs" 479 | 480 | 481 | let nm_libstubs nm = 482 | nm^"_stubs" 483 | 484 | 485 | let dispatch t e = 486 | let env = 487 | BaseEnvLight.load 488 | ~filename:env_filename 489 | ~allow_empty:true 490 | () 491 | in 492 | match e with 493 | | Before_options -> 494 | let no_trailing_dot s = 495 | if String.length s >= 1 && s.[0] = '.' then 496 | String.sub s 1 ((String.length s) - 1) 497 | else 498 | s 499 | in 500 | List.iter 501 | (fun (opt, var) -> 502 | try 503 | opt := no_trailing_dot (BaseEnvLight.var_get var env) 504 | with Not_found -> 505 | Printf.eprintf "W: Cannot get variable %s\n" var) 506 | [ 507 | Options.ext_obj, "ext_obj"; 508 | Options.ext_lib, "ext_lib"; 509 | Options.ext_dll, "ext_dll"; 510 | ] 511 | 512 | | After_rules -> 513 | (* Declare OCaml libraries *) 514 | List.iter 515 | (function 516 | | nm, [], intf_modules -> 517 | ocaml_lib nm; 518 | let cmis = 519 | List.map (fun m -> (String.uncapitalize m) ^ ".cmi") 520 | intf_modules in 521 | dep ["ocaml"; "link"; "library"; "file:"^nm^".cma"] cmis 522 | | nm, dir :: tl, intf_modules -> 523 | ocaml_lib ~dir:dir (dir^"/"^nm); 524 | List.iter 525 | (fun dir -> 526 | List.iter 527 | (fun str -> 528 | flag ["ocaml"; "use_"^nm; str] (S[A"-I"; P dir])) 529 | ["compile"; "infer_interface"; "doc"]) 530 | tl; 531 | let cmis = 532 | List.map (fun m -> dir^"/"^(String.uncapitalize m)^".cmi") 533 | intf_modules in 534 | dep ["ocaml"; "link"; "library"; "file:"^dir^"/"^nm^".cma"] 535 | cmis) 536 | t.lib_ocaml; 537 | 538 | (* Declare directories dependencies, replace "include" in _tags. *) 539 | List.iter 540 | (fun (dir, include_dirs) -> 541 | Pathname.define_context dir include_dirs) 542 | t.includes; 543 | 544 | (* Declare C libraries *) 545 | List.iter 546 | (fun (lib, dir, headers) -> 547 | (* Handle C part of library *) 548 | flag ["link"; "library"; "ocaml"; "byte"; tag_libstubs lib] 549 | (S[A"-dllib"; A("-l"^(nm_libstubs lib)); A"-cclib"; 550 | A("-l"^(nm_libstubs lib))]); 551 | 552 | flag ["link"; "library"; "ocaml"; "native"; tag_libstubs lib] 553 | (S[A"-cclib"; A("-l"^(nm_libstubs lib))]); 554 | 555 | flag ["link"; "program"; "ocaml"; "byte"; tag_libstubs lib] 556 | (S[A"-dllib"; A("dll"^(nm_libstubs lib))]); 557 | 558 | (* When ocaml link something that use the C library, then one 559 | need that file to be up to date. 560 | This holds both for programs and for libraries. 561 | *) 562 | dep ["link"; "ocaml"; tag_libstubs lib] 563 | [dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)]; 564 | 565 | dep ["compile"; "ocaml"; tag_libstubs lib] 566 | [dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)]; 567 | 568 | (* TODO: be more specific about what depends on headers *) 569 | (* Depends on .h files *) 570 | dep ["compile"; "c"] 571 | headers; 572 | 573 | (* Setup search path for lib *) 574 | flag ["link"; "ocaml"; "use_"^lib] 575 | (S[A"-I"; P(dir)]); 576 | ) 577 | t.lib_c; 578 | 579 | (* Add flags *) 580 | List.iter 581 | (fun (tags, cond_specs) -> 582 | let spec = BaseEnvLight.var_choose cond_specs env in 583 | let rec eval_specs = 584 | function 585 | | S lst -> S (List.map eval_specs lst) 586 | | A str -> A (BaseEnvLight.var_expand str env) 587 | | spec -> spec 588 | in 589 | flag tags & (eval_specs spec)) 590 | t.flags 591 | | _ -> 592 | () 593 | 594 | 595 | let dispatch_default conf t = 596 | dispatch_combine 597 | [ 598 | dispatch t; 599 | MyOCamlbuildFindlib.dispatch conf; 600 | ] 601 | 602 | 603 | end 604 | 605 | 606 | # 606 "myocamlbuild.ml" 607 | open Ocamlbuild_plugin;; 608 | let package_default = 609 | { 610 | MyOCamlbuildBase.lib_ocaml = [("lens", [], [])]; 611 | lib_c = []; 612 | flags = []; 613 | includes = [] 614 | } 615 | ;; 616 | 617 | let conf = {MyOCamlbuildFindlib.no_automatic_syntax = false} 618 | 619 | let dispatch_default = MyOCamlbuildBase.dispatch_default conf package_default;; 620 | 621 | # 622 "myocamlbuild.ml" 622 | (* OASIS_STOP *) 623 | Ocamlbuild_plugin.dispatch dispatch_default;; 624 | -------------------------------------------------------------------------------- /opam/lens.1.0.0/descr: -------------------------------------------------------------------------------- 1 | Functional lenses 2 | Based on F# implementation in https://github.com/fsharp/fsharpx 3 | see https://github.com/fsharp/fsharpx/blob/master/src/FSharpx.Core/Lens.fs for the original implementation 4 | see http://bugsquash.blogspot.com/2011/11/lenses-in-f.html - Lenses in F# 5 | see http://stackoverflow.com/questions/8179485/updating-nested-immutable-data-structures - Stackoverflow question about Updating nested immutable data structures 6 | see http://stackoverflow.com/questions/5767129/lenses-fclabels-data-accessor-which-library-for-structure-access-and-mutatio - Haskell libraries for structure access and mutation 7 | see http://www.youtube.com/watch?v=efv0SQNde5Q - Functional lenses for Scala by Edward Kmett on YouTube 8 | see http://patternsinfp.wordpress.com/2011/01/31/lenses-are-the-coalgebras-for-the-costate-comonad - Lenses are the coalgebras for the costate comonad by Jeremy Gibbons 9 | -------------------------------------------------------------------------------- /opam/lens.1.0.0/findlib: -------------------------------------------------------------------------------- 1 | lens 2 | -------------------------------------------------------------------------------- /opam/lens.1.0.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "1.2" 2 | name: "lens" 3 | version: "1.0.0" 4 | maintainer: "Paolo Donadeo " 5 | authors: [ "Alessandro Strada " ] 6 | license: "BSD-3-clause" 7 | homepage: "https://github.com/pdonadeo/ocaml-lens" 8 | build: [ 9 | ["ocaml" "setup.ml" "-configure" "--prefix" prefix] 10 | ["ocaml" "setup.ml" "-build"] 11 | ] 12 | install: ["ocaml" "setup.ml" "-install"] 13 | remove: [ 14 | ["ocamlfind" "remove" "lens"] 15 | ] 16 | depends: [ 17 | "ocamlfind" 18 | ] 19 | -------------------------------------------------------------------------------- /opam/lens.1.0.0/url: -------------------------------------------------------------------------------- 1 | archive: "https://github.com/pdonadeo/ocaml-lens/archive/v1.0.0.tar.gz" 2 | checksum: "ab26edc935c0b350a5ae7b714142a724" 3 | --------------------------------------------------------------------------------