Created
April 22, 2016 20:28
-
-
Save mrange/1b11322f9a10cffd3168a6e8376e2ed1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Lenses = | |
// A Lens is a type that allows "focusing" on a property of a type | |
// A Lens consists of a get and set function | |
// Inspired by: http://www.haskellforall.com/2012/01/haskell-for-mainstream-programmers_28.html | |
// getter setter | |
type Lens<'T, 'V> = Lens of ('T -> 'V)*('V -> 'T -> 'T) | |
let inline get (Lens (g, _)) v = g v | |
let inline set (Lens (_, s)) n v = s n v | |
// >-> chains two Lenses, allows focusing on property of a property of a type | |
let ( >-> ) (f : Lens<'T, 'V>) (s : Lens<'V, 'U>) : Lens<'T, 'U> = | |
Lens (get f >> get s, fun n v -> set f (set s n (get f v)) v) | |
// fstL is a Lens that focuses on the first element in a pair | |
let fstL<'T, 'U> : Lens<'T*'U, 'T> = | |
Lens (fst, fun n v -> (n, snd v)) | |
// sndL is a Lens that focuses on the second element in a pair | |
let sndL<'T, 'U> : Lens<'T*'U, 'U> = | |
Lens (snd, fun n v -> (fst v, n)) | |
// mapzL is a Lens that focuses on an element in a map, z is the zero value if not present | |
let mapzL k z : Lens<Map<'K, 'V>, 'V> = | |
let get v = | |
match Map.tryFind k v with | |
| Some e -> e | |
| _ -> z | |
let set = Map.add k | |
Lens (get, set) | |
// mapzL is a Lens that focuses on an element in a map | |
let inline mapL k = mapzL k LanguagePrimitives.GenericZero | |
open Lenses | |
[<EntryPoint>] | |
let main argv = | |
// Creates an empty map of a map | |
let empty : Map<string, Map<int, float>> = Map.empty | |
// Uses Lenses to update the map | |
// Has to pass Map.empty to mapzL as Map doesn't have a Zero member | |
let modified1 = empty |> set (mapzL "A" Map.empty >-> mapL 2) 3. | |
let modified2 = modified1 |> set (mapzL "B" Map.empty >-> mapL 3) 4. | |
let modified3 = modified2 |> set (mapzL "B" Map.empty >-> mapL 4) 5. | |
printfn "%A" empty | |
printfn "%A" modified1 | |
printfn "%A" modified2 | |
printfn "%A" modified3 | |
0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment