F# Scribbles

My experiments with F#

Copying or modifying immutable nested record

This is just a simple code snippet to show case how to copy or modify a immutable nested record type.

Let us define a nested type

1
2
3
4
type Address = {no: int; street: string; city: string; zip: string}

type Profile = {name: string; address: Address}
                 member this.tos() = sprintf "%s. %d - %s, %s %s" this.name this.address.no this.address.street this.address.city this.address.zip

The Profile contains Address type. Let us create an instance.

1
let profile = {name = "Sheik"; address = {no = 1; street = "Road"; city = "Chennai"; zip = "600001"}}

If you want to change the street name alone for profile

1
let mprofile = {profile with address = {profile.address with street = "Nungambakkam High Road"}}

The result will be

1
2
3
4
5
> profile.tos()
val it : string = "Sheik. 1 - Road, Chennai 600001"

> mprofile.tos()
val it : string = "Sheik. 1 - Nungambakkam High Road, Chennai 600001"

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

Generate plain item list from a catalog in a web page

As part of my IoT related experiments, reading Exploring Ardunio book for some insight. In order to get the list of electronic parts for the projects, http://exploringarduino.com/parts list out all required items. Here the excercise to take the HTML of the catalog from the web site using Chrome and then used F# script to get the plain list.

In the HTML, you can see the item title in the format of “title={item name}”

I define a regex to parse that specific item on every line.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
open System
open System.IO
open System.Text.RegularExpressions

let parseLine (line: string) =
    let r = Regex.Match (line, """.*(title=\"(.*)\").*""")
    r.Groups.[2].Value

let parse text =
    let foldit seq = Seq.fold (fun acc l -> acc + Environment.NewLine + parseLine(l)) "" seq
    text |> foldit

let writefile content = File.WriteAllText(__OUTPUT__FILE, content)
File.ReadLines(__INPUT_FILE__)
    |> parse
    |> writefile

Here, the outcome

1
2
3
4
5
6
7
8
9
.1uF Electrolytic Capacitor
100 ohm Resistor
10kohm Potentiometer
10kohm Resistor
10uF Electrolytic Capacitor
150ohm Resistor
16x2 LCD
1kohm Resistor
...

Performance of large list on reverse function using F# and Scala

1000000 100000000 let l = [1..100000000];; Real: 00:00:32.954, CPU: 00:00:34.593, GC gen0: 1030, gen1: 520, gen2: 9

val l : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20; 21; 22; 23; 24; 25; 26; 27; 28; 29; 30; 31; 32; 33; 34; 35; 36; 37; 38; 39; 40; 41; 42; 43; 44; 45; 46; 47; 48; 49; 50; 51; 52; 53; 54; 55; 56; 57; 58; 59; 60; 61; 62; 63; 64; 65; 66; 67; 68; 69; 70; 71; 72; 73; 74; 75; 76; 77; 78; 79; 80; 81; 82; 83; 84; 85; 86; 87; 88; 89; 90; 91; 92; 93; 94; 95; 96; 97; 98; 99; 100; …]

reverse l;; Real: 00:01:05.544, CPU: 00:00:59.031, GC gen0: 517, gen1: 260, gen2: 14 val it : int list = [100000000; 99999999; 99999998; 99999997; 99999996; 99999995; 99999994; 99999993; 99999992; 99999991; 99999990; 99999989; 99999988; 99999987; 99999986; 99999985; 99999984; 99999983; 99999982; 99999981; 99999980; 99999979; 99999978; 99999977; 99999976; 99999975; 99999974; 99999973; 99999972; 99999971; 99999970; 99999969; 99999968; 99999967; 99999966; 99999965; 99999964; 99999963; 99999962; 99999961; 99999960; 99999959; 99999958; 99999957; 99999956; 99999955; 99999954; 99999953; 99999952; 99999951; 99999950; 99999949; 99999948; 99999947; 99999946; 99999945; 99999944; 99999943; 99999942; 99999941; 99999940; 99999939; 99999938; 99999937; 99999936; 99999935; 99999934; 99999933; 99999932; 99999931; 99999930; 99999929; 99999928; 99999927; 99999926; 99999925; 99999924; 99999923; 99999922; 99999921; 99999920; 99999919; 99999918; 99999917; 99999916; 99999915; 99999914; 99999913; 99999912; 99999911; 99999910; 99999909; 99999908; 99999907; 99999906; 99999905; 99999904; 99999903; 99999902; 99999901; …]

Reverse a list elements with plain code

How to reverse a list elements

1
2
3
4
5
6
let reverse list =
        let rec rev rlist list =
            hmatch list with
            | [] -> rlist
            | h :: t -> rev (h :: rlist) t
        rev [] list

The “rev” is the inner function to recursively get the head of given list and prepend to the result.

1
2
let l = [1; 3; 5];;
reverse l;;

results [5; 3; 1]