Skip to content

Instantly share code, notes, and snippets.

@mrange
Created April 22, 2016 20:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrange/1b11322f9a10cffd3168a6e8376e2ed1 to your computer and use it in GitHub Desktop.
Save mrange/1b11322f9a10cffd3168a6e8376e2ed1 to your computer and use it in GitHub Desktop.
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