F# Computation Expression - Type woes

338 views Asked by At

I'm fighting with a few pathetic lines of code but cannot wrap my head around the problem - for whatever reason I can't get under the principle of this aspect of F#'s type system and so far all my reading hasn't worked.

Can anyone point out to me the rather stupid schoolboy error I'm making here? I know I am making one, I just cannot see it! I'm trying to climb out of painful beginner land on this, so grokking the full principle of why this doesn't work is my aim - any help would be gratefully received!

It's a simple exercise - just a practice one actually that doesn't really need a monad to perform, however I really want these things under my belt for my next project.

let stringToInt str = Int32.TryParse(str)

type wk() =
    member this.Bind(f , str) = f str
    member this.Return(f ) = f 

let strInt = new wk()

let test a   =  strInt{let! b  = strInt.Bind a stringToInt 
                   return b}


let x = test  "10"  
printfn "%s" x

I'm getting the following:

Program.fs(117,14): error FS0001: This expression was expected to have type
(string -> bool * int) -> ('a -> 'a) -> 'b    
but here has type  string 

Update: Based on help from below, I have this working now:

 open System
 open System.Threading

 let stringToInt str = snd <| Int32.TryParse(str)   


 type wk() =
   member this.Bind(funct, str) =  funct str  
   member this.Return(str) = str

   let strInt = new wk()
   //Jack P syntax!
   let test2 str funct = strInt{
                         let! b = funct str
                         return b
                               }
   let go2 = test2 ("10", stringToInt) |>  printfn "%A"

Though working is perhaps still not conceptually there yet - getting the value to print doesn't happen. I'll keep hacking through - I've done tons of reading, that's where I got the exercise from but the only way I'll get the concept is to continue to fight with it I think.

I succeeded in a simpler form on my blog: http://richardgriffiths.azurewebsites.net/?p=2332 so I just need to bust the syntax/concept barrier I've got with the type system.

2

There are 2 answers

0
kvb On

You've defined Bind to take a tupled argument (which is correct for a computation builder), but you're passing the arguments in curried form (strInt.Bind a stringToInt instead of strInt.Bind(a, stringToInt)).

2
Jack P. On

The whole point of computation expressions in F# is that you don't have to explicitly call the Bind, Return, etc. methods on your builder instance (strInt in your case). That's the difference between let and let! -- in a computation expression, let! bindings are compiled so they call the Bind method of the builder instance. So you'd write your code like this:

let test a =
    strInt {
    let! b  = stringToInt a
    return b
    }

However -- the code above still doesn't work because your Bind and Return methods aren't defined correctly (they're not monadic). I second Patryk's suggestion (in his comment) -- you should spend some time practicing with the simple, common monads (e.g., option) before you start trying to write your own. It's easy to use F# computation expressions, but defining your own computation expressions is an intermediate/advanced-level topic.