Handy F# snippets


14 Answers

Multi-Line Strings

This is pretty trivial, but it seems to be a feature of F# strings that is not widely known.

let sql = "select a,b,c \
           from table \
           where a = 1"

This produces:

val sql : string = "select a,b,c from table where a = 1"

When the F# compiler sees a back-slash followed by a carriage return inside a string literal, it will remove everything from the back-slash to the first non-space character on the next line. This allows you to have multi-line string literals that line up, without using a bunch of string concatenation.

Question

There are already two questions about F#/functional snippets.

However what I'm looking for here are useful snippets, little 'helper' functions that are reusable. Or obscure but nifty patterns that you can never quite remember.

Something like:

open System.IO

let rec visitor dir filter= 
    seq { yield! Directory.GetFiles(dir, filter)
          for subdir in Directory.GetDirectories(dir) do 
              yield! visitor subdir filter} 

I'd like to make this a kind of handy reference page. As such there will be no right answer, but hopefully lots of good ones.

EDIT Tomas Petricek has created a site specifically for F# snippets http://fssnip.net/.




Flatten a List

if you have something like this:

let listList = [[1;2;3;];[4;5;6]] 

and want to 'flatten' it down to a singe list so the result is like this:

[1;2;3;4;5;6]

it can be done thusly:

let flatten (l: 'a list list) =
    seq {
            yield List.head (List.head l) 
            for a in l do yield! (Seq.skip 1 a) 
        } 

    |> List.ofSeq



'Unitize' a function which doesn't handle units Using the FloatWithMeasure function http://msdn.microsoft.com/en-us/library/ee806527(VS.100).aspx.

let unitize (f:float -> float) (v:float<'u>) =
  LanguagePrimitives.FloatWithMeasure<'u> (f (float v))

Example:

[<Measure>] type m
[<Measure>] type kg

let unitize (f:float -> float) (v:float<'u>) =
  LanguagePrimitives.FloatWithMeasure<'u> (f (float v))

//this function doesn't take units
let badinc a = a + 1.

//this one does!
let goodinc v = unitize badinc v

goodinc 3.<m>
goodinc 3.<kg>

OLD version:

let unitize (f:float -> float) (v:float<'u>) =
  let unit = box 1. :?> float<'u>
  unit * (f (v/unit))

Kudos to kvb




Creating XElements

Nothing amazing, but I keep getting caught out by the implicit conversion of XNames:

#r "System.Xml.Linq.dll"
open System.Xml.Linq

//No! ("type string not compatible with XName")
//let el = new XElement("MyElement", "text") 

//better
let xn s = XName.op_Implicit s
let el = new XElement(xn "MyElement", "text")

//or even
let xEl s o = new XElement(xn s, o)
let el = xEl "MyElement" "text"



OK, this has nothing to do with snippets, but I keep forgetting this:

If you are in the interactive window, you hit F7 to jump back to the code window (without deselecting the code which you just ran...)

Going from code window to F# window (and also to open the F# window) is Ctrl Alt F

(unless CodeRush has stolen your bindings...)




Transposing a list (seen on Jomo Fisher's blog)

///Given list of 'rows', returns list of 'columns' 
let rec transpose lst =
    match lst with
    | (_::_)::_ -> List.map List.head lst :: transpose (List.map List.tail lst)
    | _         -> []

transpose [[1;2;3];[4;5;6];[7;8;9]] // returns [[1;4;7];[2;5;8];[3;6;9]]

And here is a tail-recursive version which (from my sketchy profiling) is mildly slower, but has the advantage of not throwing a when the inner lists are longer than 10000 elements (on my machine):

let transposeTR lst =
  let rec inner acc lst = 
    match lst with
    | (_::_)::_ -> inner (List.map List.head lst :: acc) (List.map List.tail lst)
    | _         -> List.rev acc
  inner [] lst

If I was clever, I'd try and parallelise it with async...




Naive CSV reader (i.e., won't handle anything nasty)

(Using filereadlines and List.transpose from other answers here)

///Given a file path, returns a List of row lists
let ReadCSV = 
        filereadlines
            >> Array.map ( fun line -> line.Split([|',';';'|]) |> List.ofArray )
            >> Array.toList

///takes list of col ids and list of rows, 
///   returns array of columns (in requested order)
let GetColumns cols rows = 
    //Create filter
    let pick cols (row:list<'a>) = List.map (fun i -> row.[i]) cols

    rows 
        |> transpose //change list of rows to list of columns
        |> pick cols      //pick out the columns we want
        |> Array.ofList  //an array output is easier to index for user

Example

"C:\MySampleCSV"
   |> ReadCSV
   |> List.tail //skip header line
   |> GetColumns [0;3;1]  //reorder columns as well, if needs be.



Handling arguments in a command line application:

//We assume that the actual meat is already defined in function 
//    DoStuff (string -> string -> string -> unit)
let defaultOutOption = "N"
let defaultUsageOption = "Y"

let usage =  
      "Scans a folder for and outputs results.\n" +
      "Usage:\n\t MyApplication.exe FolderPath [IncludeSubfolders (Y/N) : default=" + 
      defaultUsageOption + "] [OutputToFile (Y/N): default=" + defaultOutOption + "]"

let HandlArgs arr = 
    match arr with
        | [|d;u;o|] -> DoStuff d u o
        | [|d;u|] -> DoStuff d u defaultOutOption 
        | [|d|] -> DoStuff d defaultUsageOption defaultOutOption 
        | _ ->  
            printf "%s" usage
            Console.ReadLine() |> ignore

[<EntryPoint>]
let main (args : string array) = 
    args |> HandlArgs
    0

(I had a vague memory of this technique being inspired by Robert Pickering, but can't find a reference now)




Generic memoization, courtesy of the man himself

let memoize f = 
  let cache = System.Collections.Generic.Dictionary<_,_>(HashIdentity.Structural)
  fun x ->
    let ok, res = cache.TryGetValue(x)
    if ok then res
    else let res = f x
         cache.[x] <- res
         res

Using this, you could do a cached reader like so:

let cachedReader = memoize reader



toggle code to sql

More trivial than most on this list, but handy nonetheless:

I'm always taking sql in and out of code to move it to a sql environment during development. Example:

let sql = "select a,b,c "
    + "from table "
    + "where a = 1"

needs to be 'stripped' to:

select a,b,c
from table
where a = 1

keeping the formatting. It's a pain to strip out the code symbols for the sql editor, then put them back again by hand when I've got the sql worked out. These two functions toggle the sql back and forth from code to stripped:

// reads the file with the code quoted sql, strips code symbols, dumps to FSI
let stripForSql fileName = 
    File.ReadAllText(fileName)
    |> (fun s -> Regex.Replace(s, "\+(\s*)\"", "")) 
    |> (fun s -> s.Replace("\"", ""))
    |> (fun s -> Regex.Replace(s, ";$", "")) // end of line semicolons
    |> (fun s -> Regex.Replace(s, "//.+", "")) // get rid of any comments
    |> (fun s -> printfn "%s" s)

then when you are ready to put it back into your code source file:

let prepFromSql fileName = 
    File.ReadAllText(fileName)
    |> (fun s -> Regex.Replace(s, @"\r\n", " \"\r\n+\"")) // matches newline 
    |> (fun s -> Regex.Replace(s, @"\A", " \"")) 
    |> (fun s -> Regex.Replace(s, @"\z", " \"")) 
    |> (fun s -> printfn "%s" s)

I'd love to get rid of the input file but can't even begin to grok how to make that happen. anyone?

edit:

I figured out how to eliminate the requirement of a file for these functions by adding a windows forms dialog input/output. Too much code to show, but for those who would like to do such a thing, that's how I solved it.




Weighted sum of arrays

Calculating a weighted [n-array] sum of a [k-array of n-arrays] of numbers, based on a [k-array] of weights

(Copied from this question, and kvb's answer)

Given these arrays

let weights = [|0.6;0.3;0.1|]

let arrs = [| [|0.0453;0.065345;0.07566;1.562;356.6|] ; 
           [|0.0873;0.075565;0.07666;1.562222;3.66|] ; 
           [|0.06753;0.075675;0.04566;1.452;3.4556|] |]

We want a weighted sum (by column), given that both dimensions of the arrays can be variable.

Array.map2 (fun w -> Array.map ((*) w)) weights arrs 
|> Array.reduce (Array.map2 (+))

First line: Partial application of the first Array.map2 function to weights yields a new function (Array.map ((*) weight) which is applied (for each weight) to each array in arr.

Second line: Array.reduce is like fold, except it starts on the second value and uses the first as the initial 'state'. In this case each value is a 'line' of our array of arrays. So applying an Array.map2 (+) on the first two lines means that we sum the first two arrays, which leaves us with a new array, which we then (Array.reduce) sum again onto the next (in this case last) array.

Result:

[|0.060123; 0.069444; 0.07296; 1.5510666; 215.40356|]



For performance intensive stuff where you need to check for null

let inline isNull o = System.Object.ReferenceEquals(o, null)
if isNull o then ... else ...

Is about 20x faster then

if o = null then ... else ...



Tree-sort / Flatten a tree into a list

I have the following binary tree:

             ___ 77 _
            /        \
   ______ 47 __       99
  /            \
21 _          54
    \        /  \
      43    53  74
     /
    39
   /
  32

Which is represented as follows:

type 'a tree =
    | Node of 'a tree * 'a * 'a tree
    | Nil

let myTree =
    Node
      (Node
         (Node (Nil,21,Node (Node (Node (Nil,32,Nil),39,Nil),43,Nil)),47,
          Node (Node (Nil,53,Nil),54,Node (Nil,74,Nil))),77,Node (Nil,99,Nil))

A straightforward method to flatten the tree is:

let rec flatten = function
    | Nil -> []
    | Node(l, a, r) -> flatten l @ a::flatten r

This isn't tail-recursive, and I believe the @ operator causes it to be O(n log n) or O(n^2) with unbalanced binary trees. With a little tweaking, I came up with this tail-recursive O(n) version:

let flatten2 t =
    let rec loop acc c = function
        | Nil -> c acc
        | Node(l, a, r) ->
            loop acc (fun acc' -> loop (a::acc') c l) r
    loop [] (fun x -> x) t

Here's the output in fsi:

> flatten2 myTree;;
val it : int list = [21; 32; 39; 43; 47; 53; 54; 74; 77; 99]



Parallel map

let pmap f s =
    seq { for a in s -> async { return f s } }
    |> Async.Parallel
    |> Async.Run



Maybe monad

type maybeBuilder() =
    member this.Bind(v, f) =
        match v with
        | None -> None
        | Some(x) -> f x
    member this.Delay(f) = f()
    member this.Return(v) = Some v

let maybe = maybeBuilder()

Here's a brief intro to monads for the uninitiated.






Related