Here is Explanation of Monad laws in Haskell.
How do explain Monad laws in F#?
bind (M, return) is equivalent to M.
bind ((return x), f) is equivalent to f x.
bind (bind (m, f),g) is equivalent to bind(m, (fun x -> bind (f x, g))).
I think that a good way to understand them in F# is to look at what they mean using the computation expression syntax. I'll write m for some computation builder, but you can imagine that this is async or any other computation type.
Left identity
m { let! x' = m { return x } = m { let x' = x
return! f x' } return! f x' }
Right identity
m { let! x = comp = m { return! comp }
return x }
Associativity
m { let! x = comp = m { let! y = m { let! x = comp
let! y = f x return! f x }
return! g y } return! g y }
The laws essentially tell you that you should be able to refactor one version of the program to the other without changing the meaning - just like you can refactor ordinary F# programs.
Related
I am trying to make a builder using FSharp Computation Expression, but get error FS0039:
type UpdatebBuilder() =
member this.Yield (x) = x
member this.Return (x) = x
member this.Bind (x, cont) = cont(x)
member this.Quote (x) = x
member this.For (x, a) = x
[<CustomOperation("set", MaintainsVariableSpace =true,AllowIntoPattern=true)>]
member this.Set (x, a, b) = x
let update = UpdatebBuilder()
let testUpdate () =
update {
for x in [| 1; 2 ; 3|] do
set x 123 // Compile Error FS0039: The value or constructor 'x' is not defined.
}
What I want to implement is something like query expression:
query {
for x in collection do
where x = 2 // Why no FS0039 error here?
select x
}
Also tried MaintainsVariableSpaceUsingBind=true, and get same error. What should I do to make it compile?
To me it looks like you are trying to define a State monad and implementing the Set operation as a custom operation.
I will admit I never fully got my head around custom operations in F# (and I used F# alot). IMHO it feels like custom operations had one purpose; enable a LINQ like syntax in F#. As time goes in it seems few C# developers are using the LINQ like syntax (ie from x where y select z) and few F# developers are using the query computation expression. I have no data here but just goes from example code I see.
This could explain why the documentation on custom operations are often succinct and hard to grasp. What does this even mean? MaintainsVariableSpaceUsingBind: Indicates if the custom operation maintains the variable space of the query or computation expression through the use of a bind operation.
Anyway, so in order to learn a bit more about custom operations I tried to implement the state monad with a custom operation for set and I got a bit farther but ran into a problem which I think is an intentional limitation of the compiler. Still thought I share it with the hope that it helps OP get a bit further.
I chose this definition for State<_>:
type [<Struct>] State<'T> = S of (Map<string, obj> -> 'T*Map<string, obj>)
State<_> is a function that given a global state (a map) produces a value (that could derive from the global state but not necessarily) and a potentially updated global state.
return or value as I tend to call it as return is an F# keyword is easy to define as we just return v and the non-updated global state:
let value v = S <| fun m -> v, m
bind is useful to bind several state computations together. First run t on the global state and from the returned value create the second computation and run the updated global state through it:
let bind uf (S t) = S <| fun m ->
let tv, tm = t m
let (S u) = uf tv
u tm
get and set are used to interact with the global state:
let get k : State<'T option> = S <| fun m ->
match m |> Map.tryFind k with
| Some (:? 'T as v) -> Some v, m
| _ -> None, m
let set k v = S <| fun m ->
let m = m |> Map.add k (box v)
(), m
I created some other methods as well but in the end the builder was created like this:
type Builder() =
class
member x.Bind (t, uf) = bind uf t
member x.Combine (t, u) = combine u t
member x.Delay tf = delay tf
member x.For (s, tf) = forEach s tf
member x.Return v = value v
member x.ReturnFrom t = t : State<'T>
member x.Yield v = value v
member x.Zero () = value ()
[<CustomOperation("set", MaintainsVariableSpaceUsingBind = true)>]
member x.Set (s, k, v) = s |> combine (set k v)
end
I used MaintainsVariableSpaceUsingBind because otherwise it doesn't see v. MaintainsVariableSpace yields strange errors asking for seq types which I vaguely suspect is an optimization for computations based around seq. Checking the generated code is seems to do the right thing in that it binds the custom operations together using my bind function in the proper order.
I am now ready to do define a state computation
state {
// Works fine
set "key" -1
for v in 0..2 do
// Won't work because: FS3086: A custom operation may not be used in conjunction with 'use', 'try/with', 'try/finally', 'if/then/else' or 'match' operators within this computation expression
set "hello" v
return! State.get "key"
}
Unfortunately the compiler stops me from using custom ops in conditional operations like if, try and also for (even though it's not in the list it's conditional in some sense). This seems to be an intentional limitation. It's possible to workaround it but it feels meh
state {
set "key" -1
for v in 0..2 do
// Meh
do! state { set "key" v }
return! State.get "key"
}
IMHO I prefer just using normal do!/let! over custom operations:
state {
for v in 0..2 do
do! State.set "key" v
return! State.get "key"
}
So not really a proper answer to the question from OP but perhaps it can help you get a bit further?
Full source code:
type [<Struct>] State<'T> = S of (Map<string, obj> -> 'T*Map<string, obj>)
module State =
let value v = S <| fun m -> v, m
let bind uf (S t) = S <| fun m ->
let tv, tm = t m
let (S u) = uf tv
u tm
let combine u (S t) = S <| fun m ->
let _, tm = t m
let (S u) = u
u tm
let delay tf = S <| fun m ->
let (S t) = tf ()
t m
let forEach s tf = S <| fun m ->
let mutable a = m
for v in s do
let (S t) = tf v
let (), tm = t m
a <- tm
(), a
let get k : State<'T option> = S <| fun m ->
match m |> Map.tryFind k with
| Some (:? 'T as v) -> Some v, m
| _ -> None, m
let set k v = S <| fun m ->
let m = m |> Map.add k (box v)
(), m
let run (S t) m = t m
type Builder() =
class
member x.Bind (t, uf) = bind uf t
member x.Combine (t, u) = combine u t
member x.Delay tf = delay tf
member x.For (s, tf) = forEach s tf
member x.Return v = value v
member x.ReturnFrom t = t : State<'T>
member x.Yield v = value v
member x.Zero () = value ()
[<CustomOperation("set", MaintainsVariableSpaceUsingBind = true)>]
member x.Set (s, k, v) = s |> combine (set k v)
end
let state = State.Builder ()
let testUpdate () =
state {
// Works fine
set "key" -1
for v in 0..2 do
// Won't work because: FS3086: A custom operation may not be used in conjunction with 'use', 'try/with', 'try/finally', 'if/then/else' or 'match' operators within this computation expression
// set "hello" v
// Workaround but kind of meh
// do! state { set "key" v }
// Better IMHO
do! State.set "key" v
return! State.get "key"
}
[<EntryPoint>]
let main argv =
let tv, tm = State.run (testUpdate ()) Map.empty
printfn "v:%A" tv
printfn "m:%A" tm
0
Let's say I have this Quotation of type Quotations.Expr<(int -> int -> int)>
<# fun x y -> x + y #>
I want to create a function fun reduce x expr that when called as reduce 1 expr would essentially yield
<# fun y -> 1 + y #>
i.e. I want to partially apply a quotation to produce another quotation.
I'm sure this is doable, does anyone have any thoughts? Has this been attempted before? Can't seem to find anything.
Also I'm not very familiar with LISP -- but is this essentially similar to what I can achieve with LISP macros?
UPDATE:
While reducing the quotation, I would like to evaluate parts that can be evaluated in the resulting expression tree.
For example: reduce true <# fun b x y -> if b then x + y else x - y#> should result in <# fun x y -> x + y #>.
If you know that your quotation is of the form fun x ... then it's easy:
let subst (v:'a) (Patterns.Lambda(x,b) : Expr<'a->'b>) =
b.Substitute(fun x' -> if x = x' then Some (Expr.Value v) else None)
|> Expr.Cast<'b>
subst 1 <# fun x y -> x + y #>
If you additionally want to simplify expressions, then there are some slightly tricky questions you'll need to answer:
Do you care about side effects? If I start with <# fun x y -> printfn "%i" x #> and I substitute in 1 for x, then what's the simplified version of <# fun y -> printfn "%i" 1 #>? This should print out 1 every time it's invoked, but unless you know ahead of time which expressions might cause side effects then you can almost never simplify anything. If you ignore this (assuming no expression causes side effects) then things become much simpler at the cost of fidelity.
What does simplification really mean? Let's say I get <# fun y -> y + 1 #> after substitution. Then, is it good or bad to simplify this to the equivalent of let f y = y+1 in <# f #>? This is definitely "simpler" in that it's a trivial expression containing just a value, but the value is now an opaque function. What if I have <# fun y -> 1 + (fun z -> z) y #>? Is it okay to simplify the inner function to a value, or bad?
If we can ignore side effects and we don't ever want to replace a function with a value, then you could define a simplification function like this:
let reduce (e:Expr<'a>) : Expr<'a> =
let rec helper : Expr -> Expr = function
| e when e.GetFreeVars() |> Seq.isEmpty && not (Reflection.FSharpType.IsFunction e.Type) -> // no free variables, and won't produce a function value
Expr.Value(Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation e, e.Type)
| ExprShape.ShapeLambda(v, e) -> Expr.Lambda(v, helper e) // simplify body
| ExprShape.ShapeCombination(o, es) -> // simplify each subexpression
ExprShape.RebuildShapeCombination(o, es |> List.map helper)
| ExprShape.ShapeVar v -> Expr.Var v
helper e |> Expr.Cast
Note that this still might not simplify thing as much as you'd like; for example <# (fun x (y:int) -> x) 1 #> will not be simplified, although <# (fun x -> x) 1 #> will be.
Splicing is a convenient way of embedding quotations in quotations:
let reduce x expr =
<# (%expr) x #>
reduce has type 'a -> Expr<('a -> 'b)> -> Expr<'b>
Usage:
let q = <# fun x y -> x + y #>
let r = reduce 1 q // Expr<int -> int>
let s = reduce 2 <| reduce 3 q // Expr<int>
let t = reduce "world" <# sprintf "Hello %s" #> // Expr<string>
Is there an option (maybe) wokflow (monad) in the standrd F# library?
I've found a dozen of hand-made implementations (1, 2) of this workflow, but I don't really want to introduce non-standard and not very trusted code into my project. And all imaginable queries to google and msdn gave me no clue where to find it.
There's no standard computation builder for options, but if you don't need things like laziness (as added in the examples you linked) the code is straightforward enough that there's no reason not to trust it (particularly given the suggestively named Option.bind function from the standard library). Here's a fairly minimal example:
type OptionBuilder() =
member x.Bind(v,f) = Option.bind f v
member x.Return v = Some v
member x.ReturnFrom o = o
member x.Zero () = None
let opt = OptionBuilder()
There's no Maybe monad in the standard F# library. You may want to look at FSharpx, a F# extension written by highly-qualified members of F# community, which has quite a number of useful monads.
I've create an opensource library FSharp.Interop.NullOptAble available on nuget.
It not only works as an option workflow, but it works as a null or nullable workflow as well.
let x = Nullable(3)
let y = Nullable(3)
option {
let! x' = x
let! y' = y
return (x' + y')
} (* |> should equal (Some 6) *)
Works just as well as
let x = Some(3)
let y = Some(3)
option {
let! x' = x
let! y' = y
return (x' + y')
} (* |> should equal (Some 6) *)
Or even
let x = "Hello "
let y = "World"
option {
let! x' = x
let! y' = y
return (x' + y')
} (* |> should equal (Some "Hello World") *)
And if something is null or None
let x = "Hello "
let y:string = null
option {
let! x' = x
let! y' = y
return (x' + y')
} (* |> should equal None *)
Finally if you have a lot of nullable type things, I have a cexpr for chooseSeq {} and if you yield! something null/None it just doesn't get yielded.
See more examples here.
Disclosure: this came up in FsCheck, an F# random testing framework I maintain. I have a solution, but I do not like it. Moreover, I do not understand the problem - it was merely circumvented.
A fairly standard implementation of (monadic, if we're going to use big words) sequence is:
let sequence l =
let k m m' = gen { let! x = m
let! xs = m'
return (x::xs) }
List.foldBack k l (gen { return [] })
Where gen can be replaced by a computation builder of choice. Unfortunately, that implementation consumes stack space, and so eventually stack overflows if the list is long enough.The question is: why? I know in principle foldBack is not tail recursive, but the clever bunnies of the F# team have circumvented that in the foldBack implementation. Is there a problem in the computation builder implementation?
If I change the implementation to the below, everything is fine:
let sequence l =
let rec go gs acc size r0 =
match gs with
| [] -> List.rev acc
| (Gen g)::gs' ->
let r1,r2 = split r0
let y = g size r1
go gs' (y::acc) size r2
Gen(fun n r -> go l [] n r)
For completeness, the Gen type and computation builder can be found in the FsCheck source
Building on Tomas's answer, let's define two modules:
module Kurt =
type Gen<'a> = Gen of (int -> 'a)
let unit x = Gen (fun _ -> x)
let bind k (Gen m) =
Gen (fun n ->
let (Gen m') = k (m n)
m' n)
type GenBuilder() =
member x.Return(v) = unit v
member x.Bind(v,f) = bind f v
let gen = GenBuilder()
module Tomas =
type Gen<'a> = Gen of (int -> ('a -> unit) -> unit)
let unit x = Gen (fun _ f -> f x)
let bind k (Gen m) =
Gen (fun n f ->
m n (fun r ->
let (Gen m') = k r
m' n f))
type GenBuilder() =
member x.Return v = unit v
member x.Bind(v,f) = bind f v
let gen = GenBuilder()
To simplify things a bit, let's rewrite your original sequence function as
let rec sequence = function
| [] -> gen { return [] }
| m::ms -> gen {
let! x = m
let! xs = sequence ms
return x::xs }
Now, sequence [for i in 1 .. 100000 -> unit i] will run to completion regardless of whether sequence is defined in terms of Kurt.gen or Tomas.gen. The issue is not that sequence causes a stack overflow when using your definitions, it's that the function returned from the call to sequence causes a stack overflow when it is called.
To see why this is so, let's expand the definition of sequence in terms of the underlying monadic operations:
let rec sequence = function
| [] -> unit []
| m::ms ->
bind (fun x -> bind (fun xs -> unit (x::xs)) (sequence ms)) m
Inlining the Kurt.unit and Kurt.bind values and simplifying like crazy, we get
let rec sequence = function
| [] -> Kurt.Gen(fun _ -> [])
| (Kurt.Gen m)::ms ->
Kurt.Gen(fun n ->
let (Kurt.Gen ms') = sequence ms
(m n)::(ms' n))
Now it's hopefully clear why calling let (Kurt.Gen f) = sequence [for i in 1 .. 1000000 -> unit i] in f 0 overflows the stack: f requires a non-tail-recursive call to sequence and evaluation of the resulting function, so there will be one stack frame for each recursive call.
Inlining Tomas.unit and Tomas.bind into the definition of sequence instead, we get the following simplified version:
let rec sequence = function
| [] -> Tomas.Gen (fun _ f -> f [])
| (Tomas.Gen m)::ms ->
Tomas.Gen(fun n f ->
m n (fun r ->
let (Tomas.Gen ms') = sequence ms
ms' n (fun rs -> f (r::rs))))
Reasoning about this variant is tricky. You can empirically verify that it won't blow the stack for some arbitrarily large inputs (as Tomas shows in his answer), and you can step through the evaluation to convince yourself of this fact. However, the stack consumption depends on the Gen instances in the list that's passed in, and it is possible to blow the stack for inputs that aren't themselves tail recursive:
// ok
let (Tomas.Gen f) = sequence [for i in 1 .. 1000000 -> unit i]
f 0 (fun list -> printfn "%i" list.Length)
// not ok...
let (Tomas.Gen f) = sequence [for i in 1 .. 1000000 -> Gen(fun _ f -> f i; printfn "%i" i)]
f 0 (fun list -> printfn "%i" list.Length)
You're correct - the reason why you're getting a stack overflow is that the bind operation of the monad needs to be tail-recursive (because it is used to aggregate values during folding).
The monad used in FsCheck is essentially a state monad (it keeps the current generator and some number). I simplified it a bit and got something like:
type Gen<'a> = Gen of (int -> 'a)
let unit x = Gen (fun n -> x)
let bind k (Gen m) =
Gen (fun n ->
let (Gen m') = k (m n)
m' n)
Here, the bind function is not tail-recursive because it calls k and then does some more work. You can change the monad to be a continuation monad. It is implemented as a function that takes the state and a continuation - a function that is called with the result as an argument. For this monad, you can make bind tail recursive:
type Gen<'a> = Gen of (int -> ('a -> unit) -> unit)
let unit x = Gen (fun n f -> f x)
let bind k (Gen m) =
Gen (fun n f ->
m n (fun r ->
let (Gen m') = k r
m' n f))
The following example will not stack overflow (and it did with the original implementation):
let sequence l =
let k m m' =
m |> bind (fun x ->
m' |> bind (fun xs ->
unit (x::xs)))
List.foldBack k l (unit [])
let (Gen f) = sequence [ for i in 1 .. 100000 -> unit i ]
f 0 (fun list -> printfn "%d" list.Length)
Some background first. I am currently learning some stuff about monadic parser combinators. While I tried to transfer the 'chainl1' function from this paper (p. 16-17), I came up with this solution:
let chainl1 p op = parser {
let! x = p
let rec chainl1' (acc : 'a) : Parser<'a> =
let p' = parser {
let! f = op
let! y = p
return! chainl1' (f acc y)
}
p' <|> succeed acc
return! chainl1' x
}
I tested the function with some large input and got a StackOverflowException. Now I am wondering, is it posible to rewrite a recursive function, that uses some computation expression, in a way so it is using tail recursion?
When I expand the computation expression, I can not see how it would be generally possible.
let chainl1 p op =
let b = parser
b.Bind(p, (fun x ->
let rec chainl1' (acc : 'a) : Parser<'a> =
let p' =
let b = parser
b.Bind(op, (fun f ->
b.Bind(p, (fun y ->
b.ReturnFrom(chainl1' (f acc y))))))
p' <|> succeed acc
b.ReturnFrom(chainl1' x)))
In your code, the following function isn't tail-recursive, because - in every iteration - it makes a choice between either p' or succeed:
// Renamed a few symbols to avoid breaking SO code formatter
let rec chainl1Util (acc : 'a) : Parser<'a> =
let pOp = parser {
let! f = op
let! y = p
return! chainl1Util (f acc y) }
// This is done 'after' the call using 'return!', which means
// that the 'cahinl1Util' function isn't really tail-recursive!
pOp <|> succeed acc
Depending on your implementation of parser combinators, the following rewrite could work (I'm not an expert here, but it may be worth trying this):
let rec chainl1Util (acc : 'a) : Parser<'a> =
// Succeeds always returning the accumulated value (?)
let pSuc = parser {
let! r = succeed acc
return Choice1Of2(r) }
// Parses the next operator (if it is available)
let pOp = parser {
let! f = op
return Choice2Of2(f) }
// The main parsing code is tail-recursive now...
parser {
// We can continue using one of the previous two options
let! cont = pOp <|> pSuc
match cont with
// In case of 'succeed acc', we call this branch and finish...
| Choice1Of2(r) -> return r
// In case of 'op', we need to read the next sub-expression..
| Choice2Of2(f) ->
let! y = p
// ..and then continue (this is tail-call now, because there are
// no operations left - e.g. this isn't used as a parameter to <|>)
return! chainl1Util (f acc y) }
In general, the pattern for writing tail-recursive functions inside computation expressions works. Something like this will work (for computation expressions that are implemented in a way that allows tail-recursion):
let rec foo(arg) = id {
// some computation here
return! foo(expr) }
As you can check, the new version matches this pattern, but the original one did not.
In general it is possible to write tail-recursive computation expressions (see 1 and 2), even with multiple let! bindings thanks to the 'delay' mechanism.
In this case the last statement of chainl1 is what gets you into a corner I think.