0

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.

Richard Griffiths
  • 758
  • 1
  • 11
  • 23
  • I'm seriously not sure what you're trying to do here. For a gentle introduction to computation expressions, maybe try to build one for `Option` type, it's simple enough and you should get the grasp of the basics... – Patryk Ćwiek Dec 24 '13 at 12:31
  • It's just an exercise - simply return the integer value of a string, if indeed if In32.TryParse(str) has an integer in it. I'm basically learning the computation expression idea, I've succeeded in an earlier example. – Richard Griffiths Dec 24 '13 at 13:29
  • I have almost never needed to create my own computation expressions. Monads in F# are not needed like they are in Haskell. If you really feel you need to understand them, though, here's a start: http://fsharpforfunandprofit.com/series/computation-expressions.html – Grundoon Dec 24 '13 at 13:54
  • @Grundoon thank you, that's one of my main sources right now. I've a project in mind that needs parallel computation - I don't want to be conceptually handicapped when thinking through how to achieve it :) – Richard Griffiths Dec 24 '13 at 14:33
  • In your updated code, you need to change the `go2` binding to: `let go2 = test2 "10" stringToInt |> printfn "%A"`. `test2` is defined in curried form (because you haven't wrapped the entire argument list in parentheses) so you need to call it accordingly. – Jack P. Dec 24 '13 at 16:36
  • @JackP. the compiler don't love me for that unfortunately. The type '('a -> 'a) -> 'b' does not match the type 'int' - I'll have to hack through this the hard way tonight :) Have a merry Xmas!! – Richard Griffiths Dec 24 '13 at 19:42

2 Answers2

4

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.

Jack P.
  • 11,487
  • 1
  • 29
  • 34
  • P - I've yet to make this syntax work for me. What I'm in part fighting is my own syntax blindness here as the compiler, of course, is far more exacting than what I started with (VB). I did a simpler exercise no trouble, this is the gate I need to bust next :) – Richard Griffiths Dec 24 '13 at 14:34
  • P - I was a bit premature, made your syntax work now :). Now just for the side effects (actually evaluate and print the result!) – Richard Griffiths Dec 24 '13 at 14:39
3

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)).

kvb
  • 54,864
  • 2
  • 91
  • 133