Skip to content

Instantly share code, notes, and snippets.

@jbtule
Last active September 25, 2019 22:20
Show Gist options
  • Save jbtule/45284eee325416759c5fcf62dfa54b95 to your computer and use it in GitHub Desktop.
Save jbtule/45284eee325416759c5fcf62dfa54b95 to your computer and use it in GitHub Desktop.
KeyValue CE for F# 4.7
(*
* This work (KeyValue CE for F# 4.7 by James Tuley),
* identified by James Tuley, is free of known copyright restrictions
* Source: https://gist.github.com/jbtule/45284eee325416759c5fcf62dfa54b95
* http://creativecommons.org/publicdomain/mark/1.0/
*)
namespace FSharp.Experimental.KeyValueCE
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
[<AutoOpen>]
module TopLevel =
type KVMetaBuilder<'T>() =
member _.Zero() = Seq.empty<string*'T>
member _.YieldFrom (value:string*'T) = seq {value}
member _.YieldFrom (value:(string*'T) seq) = value
member _.Yield([<ReflectedDefinition(true)>] value:Expr<'T>) =
match value with
| WithValue(v,_, q)->
let v' = v :?> 'T
match q with
| FieldGet(_,f) ->
seq {(f.Name, v')}
| PropertyGet(_,p,_) ->
seq {(p.Name, v')}
| ValueWithName(_,_,n) ->
seq {(n, v')}
| _ -> failwith "Only works with a simplified name."
| _ -> failwith "Badness"
member _.Combine(a: seq<string * 'T>, b: seq<string * 'T>) = Seq.concat [a;b]
member _.Delay(f) = f()
let kv<'A> = KVMetaBuilder<'A>()
type KVBoxMetaBuilder() =
member _.Zero() = Seq.empty<string*obj>
member _.YieldFrom ((k,v):string * 'T) = seq {(k,box v)}
member _.YieldFrom (value:(string*obj) seq) = value
member _.Yield([<ReflectedDefinition(true)>] value:Expr<'T>) =
match value with
| WithValue(v,_, q)->
let v' = v
match q with
| FieldGet(_,f) ->
seq {(f.Name, v')}
| PropertyGet(_,p,_) ->
seq {(p.Name, v')}
| ValueWithName(_,_,n) ->
seq {(n, v')}
| _ -> failwith "Only works with a simplified name."
| _ -> failwith "Badness"
member _.Combine(a: seq<string * obj>, b: seq<string * obj>) = Seq.concat [a;b]
member _.Delay(f) = f()
let kvbox = KVBoxMetaBuilder()
(*
* This work (KeyValue CE for F# 4.7 by James Tuley),
* identified by James Tuley, is free of known copyright restrictions
* Source: https://gist.github.com/jbtule/45284eee325416759c5fcf62dfa54b95
* http://creativecommons.org/publicdomain/mark/1.0/
*)
/// requires <LangVersion>Prewview<LangVersion> for visual studio 2019 16.3
module FSharp.Experimental.KeyValueCE.Tests
open Xunit
[<Fact>]
let ``kv basic`` () =
let one = 1
let two = 2
let record = {|three = 3|}
let actual = kv {one;two;record.three}
let expected = seq {(nameof one, one);(nameof two, two);( nameof record.three, record.three)}
Assert.Equal<string*int>(expected, actual)
[<Fact>]
let ``kvbox basic`` () =
let one = 1
let two = 2
let record = {|three = "3"|}
let actual = kvbox {one;two;record.three}
let expected = seq {(nameof one, box one);(nameof two, box two);( nameof record.three, box record.three)}
Assert.Equal<string*obj>(expected, actual)
[<Fact>]
let ``kv weird`` () =
let one = 1
let two = 2
let record = {|three = 3|}
let five = 5
let six = 6
let actual = kv {one;two;record.three;yield! ("four", 4); yield! kv {five;six}}
let expected = seq {(nameof one, one);(nameof two, two);( nameof record.three, record.three);("four",4);(nameof five, five);(nameof six, six)}
Assert.Equal<string*int>(expected, actual)
[<Fact>]
let ``kvbox weird`` () =
let one = 1
let two = 2
let record = {|three = "3"|}
let five = 5uy
let six = 6L
let actual = kvbox {one;two;record.three;yield! ("four", 4.0); yield! kvbox {five;six}}
let expected = seq {(nameof one, box one);(nameof two, box two);( nameof record.three, box record.three);("four",box 4.0);(nameof five,box five);(nameof six,box six)}
Assert.Equal<string*obj>(expected, actual)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment