Skip to content

Instantly share code, notes, and snippets.

@nickcowle
Created March 24, 2019 14:15
Show Gist options
  • Save nickcowle/55a9f94e251a4aaf318abf208644053a to your computer and use it in GitHub Desktop.
Save nickcowle/55a9f94e251a4aaf318abf208644053a to your computer and use it in GitHub Desktop.
type 'a Foo = Foo of 'a
module Foo =
let ofValue (a : 'a) : 'a Foo = Foo a
let apply (a : 'a Foo) (f : ('a -> 'b) Foo) : 'b Foo =
let (Foo f) = f
let (Foo a) = a
Foo (f a)
let map (f : 'a -> 'b) (a : 'a Foo) : 'b Foo =
ofValue f |> apply a
let map2 (f : 'a -> 'b -> 'c) (a : 'a Foo) (b : 'b Foo) : 'c Foo =
map f a |> apply b
type FooBuilder () =
member __.For (foo, f) =
Foo.map f foo
member __.Yield (a : 'a) : 'a =
a
member __.Return (a : 'a) : 'a =
a
[<CustomOperation("apply", IsLikeZip = true)>]
member __.Zip ((), foo : 'a Foo, f : unit -> 'a -> 'b) : 'b Foo =
Foo.map (f ()) foo
[<CustomOperation("also", IsLikeZip = true)>]
member __.Zip2 (foo1 : 'a Foo, foo2 : 'b Foo, f : 'a -> 'b -> 'c) : 'c Foo =
Foo.map2 f foo1 foo2
let foo = FooBuilder ()
let myFoo = Foo.ofValue 1234
let myFoo2 = Foo.ofValue false
let myFoo3 = Foo.ofValue "Hello"
let test : string Foo =
foo {
apply i in myFoo
also b in myFoo2
also s in myFoo3
return if b then sprintf "%i" i else s
}
@SchlenkR
Copy link

SchlenkR commented Mar 5, 2020

Wow, that's cool. So no let!..and?

@nickcowle
Copy link
Author

Yes, that's right - we've been using this as a workaround for the lack of support for applicative computation expression builders in F#. However, we won't need to in the future! Take a look at dotnet/fsharp#7756 - applicative computation expression builders have now been implemented and should be available as part of F# 5.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment