Monday, March 26, 2018

Magical F#

Check this out!


open System
open System.Collections.Generic
type Stats = Map<string, obj>

// Lens code based on http://www.fssnip.net/7Pk/title/Polymorphic-lenses by Vesa Karvonen

type Lens<'s,'t,'a,'b> = ('a -> Option<'b>) -> 's -> Option<'t>
module Lens =
let view l s =
let r = ref Unchecked.defaultof<_>
s |> l (fun a -> r := a; None) |> ignore
!r

let over l f =
l (f >> Some) >> function Some t -> t | _ -> failwith "Impossible"
let set l b = over l <| fun _ -> b
let lens get set = fun f s ->
(get s |> f : Option<_>) |> Option.map (fun f -> set f s)

module Props =
let prop<'t> (propName: string) f =
Lens.lens
(fun x -> match Map.tryFind propName x with | Some(v) -> (if (box v :? 't) then (v |> unbox<'t>) else Unchecked.defaultof<'t>) | _ -> Unchecked.defaultof<'t>)
(fun v x -> Map.add propName v x)
f
let set prop v stats = stats |> Lens.set prop (box v)
let get prop stats = stats |> Lens.view prop

open Props
let name = prop<string> "Name"
let id = prop<string> "ID"
let iq = prop<int> "IQ"
let me = Map.empty |> set name "Max" |> set id "30777" |> set iq 4
printfn "%s (%s) is %s" (get name me) (get id me) (if get iq me > 100 then "smart" else "not smart")
// prints "Max (30777) is not smart"
// Did you catch that? iq returns an int, not a boxed int, and name statically knows that it's returning a string! Magic!

~B.C.

--
If I esteem mankind to be in error, shall I bear them down? No. I will lift them up, and in their own way too, if I cannot persuade them my way is better; and I will not seek to compel any man to believe as I do, only by the force of reasoning, for truth will cut its own way.

"Thou shalt love thy wife with all thy heart, and shalt cleave unto her and none else."

No comments: