Hi,
the translation makes sense, because the first argument is a function that checks some condition (for while loops, this necessarily depends on some mutable state, so the function cannot be pure). The second argument is the body of the loop (which also depends on some mutable state, so binding it multiple times gives different results).

The signature you suggested would more likely represent an arbitrary recursion (start with second argument, then use the first argument to get the next 'body'). However, it would also need some way to represent end of looping (perhaps, make the signature (unit -> M option) * M -> M ). I it would also work, but I think F# tries to make the signature as simple as possible.

For most of the monads, you can use the following default implementation in terms of bind & return:

1
2
3
4
5
6
7
8
9
10
type MyBuilder() = 
  member x.Bind(v, f) = // your bind
  member x.Return(v) = // your return
  member x.Delay(f:unit -> M<'a>) : M<'a> = // your delay 
  member x.While(f, body) = 
    if f() then 
       // bind one step and continue recursively
       x.Bind(body, (fun _ -> x.While(f, body))
    // return unit value 
    else x.Return(())

For more information look at the F# specification (around page 58):
[link:research.microsoft.com]

By on 1/24/2010 12:32 PM ()

In case of the state monad, the monad type is:

1
type M<'a> = State -> 'a*State

It is used to create pure computations that apparently manipulate an impure state.

By not being able to access the monadic state in the while condition, we are restricted to extremely simple conditions which, with respect to the state, are either always true or false because there is no possible feedback between the loop body and the condition. The only option to make it possible to modify the condition inside the loop body is to use mutable variables, which makes *absolutely no sense* when dealing with a monad like state, since that's what we are avoiding in the first place (undoable computations, for example).

I believe this to be a bug. A reasonable solution would be to allow workflows to support overloaded versions of the while statement, or to add support to a keyword like

while!

which would take as a condition a boolean monad.

PS: sorry for the tone of the mail, I am a bit hasty but I absolutely don't wish to be discorteous :)

By on 1/25/2010 1:11 AM ()

A "while!" could be an interesting extension, I can imagine

1
2
3
4
 

m.WhileBang : (guard: (M<unit> -> bool * M<unit>), comp : M<unit>)

or maybe instead

1
2
3
4
 

m.WhileBang : (guard: (M<unit> -> bool), comp : M<unit>)

(where the latter guard is expected to only 'read' values from the monad but not have any 'effects' that propagate through the subsequent computation). Then the guard would itself be a computation expression rather than a normal expression.

(On the other hand, you can also argue that 'while' is an 'explicitly stateful' construct, and just don't implement the method for a state monad and require those using the state monad to write recursion.)

By on 1/25/2010 10:59 AM ()

(On the other hand, you can also argue that 'while' is an 'explicitly stateful' construct, and just don't implement the method for a state monad and require those using the state monad to write recursion.)

True, but then again one of the most important uses of monads is to model implicitly stateful constructs, so having a monadic construct that does not work well with state is strange to say the least :)

Also, it might be interesting to think about the most logical use of WhileBang in the context of the seq monad...

By on 1/25/2010 11:46 AM ()

though it seems that Haskell's monad type is using similar signature(the guard function) ?

[link:www.haskell.org]

By on 1/25/2010 7:11 PM ()

True, but in case of the guard, you could simply write:

1
2
let! b = cond // cond : M<bool>
do! if b then t else e // t : M<unit>, e : M<unit>

there is no such workaround possible for a while, apart from using explicit recursion (readability suffers a bit, though).

This said, it would be nice to have an if! too :)

By on 1/26/2010 12:24 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper