Wally
Wally

Reputation: 57

F# Monad how fix datatypes

I am trying to write a Monad in F# but I can not compile the code and I am getting error FS0001 error: This expression was expected to have type 'Result' but here has type '(Result<'a> -> Result<'b>) -> Result<'b>'

open System
type Result<'TSuccess> =
     | Success of 'TSuccess
     | Failure

let bind x f = 
    match x with 
    |  Success x -> f (Success x)
    | Failure -> Failure



let stringToInt (s:string) = 
    try
       let result = s |> int
       Success result 
    with 
       |_-> Failure 

let isPositive (i:int)  = 
    if ( i >  0) then  Success i : Result<int>
    else Failure 

let toString (i:int) = 
    try
       let result = i |> string
       Success result
    with
       |_ -> Failure

let bindIsPositive =  bind isPositive : Result<int>

let bindToString = bind toString : Result<string>

let (>>=) x f = bind f x



let strintToIntIsPositiveIntToString s =  stringToInt >>= bindIsPositive >>= bindToString

[<EntryPoint>]
let main argv =
    printfn "10"
    let mys = strintToIntIsPositiveIntToString "9"
    Console.WriteLine mys.ToString
    0 // return an integer exit code 

Upvotes: 3

Views: 86

Answers (1)

Tomas Petricek
Tomas Petricek

Reputation: 243041

First of all, the type of your bind is not right:

your version : Result<'a> -> (Result<'a> -> Result<'b>) -> Result<'b>
typical type : Result<'a> -> ('a -> Result<'b>) -> Result<'b>

It will also be a lot easier to do the rest if you switch the order of parameters to get:

bind : ('a -> Result<'b>) -> Result<'a> -> Result<'b>

So, you can use the following bind:

let bind f x = 
    match x with 
    | Success x -> f x
    | Failure -> Failure

Once you do this, you can define bindIsPositive and bindToString. The bind operation now takes a function as a first argument, so this works but you have to remove your type annotation:

let bindIsPositive =  bind isPositive 
let bindToString = bind toString

When composing functions, you can then either use your >>= operator, or use normal F# piping and bind functions:

let strintToIntIsPositiveIntToString x =  x |> stringToInt |> bindIsPositive |> bindToString
let strintToIntIsPositiveIntToString x =  x >>= stringToInt >>= isPositive >>= toString

Upvotes: 5

Related Questions