F# Scribbles

My experiments with F#

Scala's Either sum type equivalent

Gracefully propogate the result from a callee function to caller is a good practise than using exceptions or null values. Exception raising and handling are mostly not under control due to its side effect nature. Also they come up with some cost in platform like .NET and Java.

I ususally enforce my team to use Result as method return type in imperative/OO languages like C#. It has a property IsValid so that callar can ensure whether the invocation is successful. Based on this, caller will take either actual Value or Error properties appropriately. This is one of the practise in functional reactive programming.

Functional languages address this with in-build pattern like F#’s Option, and Scala’s Some/None/Option. The weakness of these approaches is not providing failure case details to the caller. Scala provides a data type called Either. You can set either an actual value as Right or error details as Left. Alvin Alexander has written an interesting article about this (http://alvinalexander.com/scala/scala-either-left-right-example-option-some-none-null).

Similar to Either, .NET 4.0 introduces TaskCompletionSource.aspx). Scala 2.x introduces a syntactic sugar of Either as Try…Success…Failure](http://www.scala-lang.org/files/archive/nightly/docs/library/index.html#scala.util.Try). This post shows the syntactic sugar for TaskCompletionSource and also how to define Either idiom in F#.

Either Equivalent

Let us define Either equivalent in F# with the help of discriminated union. I take the Alvin’s divide X by Y example here.

1
2
3
type Either<'L, 'R> =
    | Left of 'L
    | Right of 'R

Let us use this Either in the divide function as

1
2
3
4
5
6
7
8
let divide x y =
    if y = 0 then Left("Divide by zero")
    else Right(x / y )
  
let prnEither (v: Either<string, int>) =
    match v with
    | Left(s) -> printfn "Error: %s" s
    | Right(i) -> printfn "Result: %d" i

The prnEither is just a helper function to print the outcome to console.

1
2
prnEither (divide 10 0) // prints "Error: Divide by zero"
prnEither (divide 10 10) // prints "Result: 1"

Syntactic sugar for TaskCompletionSource

TaskCompletionSource provides SetException to set appropriate excpetion details and SetResult to set result if success. The below example demonstrate the usage of this in ‘sync’ way.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
exception AmountError of string

let debit(a: Account, amount: decimal) =
        // .Net way of promising and feature
      // don't worry about Account type definition here
        let tcs = new TaskCompletionSource<Account>()

        if a.balance < amount then
            tcs.SetException(AmountError "Insufficient balance in account")
        else
            tcs.SetResult({a with balance = a.balance - amount})
      // returns Task
      tcs.Task
      
let a = {no = "AnAccountNumber"; name = "Sheik"; balance = 100M}
let b = debit(a, 1000M)
b.IsFaulted // prints true
b.Exception // you may get FSI_0002+AmountError: Exception of type 'FSI_0002+AmountError' was thrown.

A syntactic sugar would be

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    type Try<'T> = TaskCompletionSource<'T>

  let Success (t: Try<'T>)  (v: 'T) = (
            t.SetResult(v)
            t)
    let SuccessAsync (t: Try<'T>)  (v: 'T) = (
            t.SetResult(v)
            Async.AwaitTask t.Task)

  let Failure (t: Try<'T>) (e: Exception) = (
            t.SetException(e)
            t)
    let FailureAsync (t: Try<'T>) (e: Exception) = (
            t.SetException(e)
            Async.AwaitTask t.Task)

And the calling side would be

1
2
3
4
5
6
7
8
let debit(a: Account, amount: decimal) =
        // .Net way of promising and feature
        let tri = new Try<Account>()

        if a.balance < amount then
            Failure tri (AmountError "Insufficient balance in account")
        else
            Success tri ({a with balance = {amount = a.balance.amount - amount}})