Difference between revisions of "FSharp"

From ScienceZero
Jump to: navigation, search
(Processing data in a functional way)
(Processing data in a functional way)
Line 146: Line 146:
  
 
==Processing data in a functional way==
 
==Processing data in a functional way==
The general idea is to run a function on every item of a colletion of items to create a new collection.
+
The seasiest method is to run a function on every item of a colletion of items to create a new collection.
 
  let a = [1..5]          // The list to process
 
  let a = [1..5]          // The list to process
 
  let mul2 n = n * 2      // Function that will be run on each item in the list
 
  let mul2 n = n * 2      // Function that will be run on each item in the list
Line 155: Line 155:
 
  This is helpful if the function is simple and only is required once.
 
  This is helpful if the function is simple and only is required once.
 
  let b = List.map (fun n -> n * 2) a  
 
  let b = List.map (fun n -> n * 2) a  
 +
 +
 +
The other method is to use a recursive function.
 +
let mul2 l =
 +
    let rec loop listIn listOut =
 +
        match listIn with
 +
        | []  -> listOut
 +
        | h::t -> loop t (h * 2 :: listOut)
 +
    List.rev (loop l [])
 +
 +
mul2 [1..5] // Gives [2;4;6;8;10]
  
  
 
[[Category:Computing]]
 
[[Category:Computing]]

Revision as of 11:33, 23 August 2013

Values and Variables

let a = 2
This is a value and it is constant within the scope of the value.
You can safely pass values to other threads, computers or to the other side of the world.
Always use values instead of variables when possible.
let mutable b = 2
This is a variable and it can be updated with a new value like in other laguanges
b <- b + 1
now b = 3

Types

The compiler will infer types in most cases.
let a = 7        - 32 bit integer
let b = "Hello"  - String
let c = 3.1415   - 64 bit floating-point
In some cases it is not possible to infer the type or you want to make a point out of it.
let a = (xPos : uint64)
A function may not always have something to return, it can then return the Option type.
if isByteReady then Some (readByte) else None
A tuple is an ordered collection of types.
let point = 100,150
The compiler will infer point as two integers.
The tuple can be decomposed by
let x,y = point
Type   Suffix  .NET Type       Range
byte       uy  System.Byte     0 to 255 
sbyte       y  System.SByte    −128 to 127 
int16       s  System.Int16    −32 768 to 32 767 
uint16     us  System.UInt16    0 to 65 535 
int, int32     System.Int32    −231 to 231 − 1 
uint32      u  System.UInt32   0 to 232 − 1 
int64       L  System.Int64    −263 to 263 − 1
uint64     UL  System.UInt64   0 to 264 − 1 
float          System.Double   64 bit floating-point IEEE 64, approximately 15 significant digits.
float32     f  System.Single   32 bit floating-point IEEE 32, approximately 7 significant digits.
decimal     M  System.Decimal  A fixed-precision floating-point type with precisely 28 digits of precision.
BigInteger  I  System.Numerics Arbitrary-sized integers 
Complex        System.Numerics Complex numbers, let (c : Complex) = new Complex(1.0, 2.0)

Functions

Everything is a function and returns a value. The last expression at the point of exit is returned to the caller.

This is a function called max that takes two integers as input and returns the larger of them.
let max a b = if a > b then a else b
if is used as a function to return a or b
If it makes no sense for a function to return a value it should return a value of type unit
let a = ()
If the value returned from a function is not required it can be deleted by using the ignore function.
like this ignore (max 1 3)
Recuresive functions must be defined with the rec keyword.

This recursive function counts down from n to 0
let rec count n =
   printfn "%A" n 
   if n = 0 then 0 else count (n - 1)
If the last statement in the function is the recursive call then the call can be converted to a jump by the compiler.

Loops

Try to avoid loops when it is simple to do so because most loops require change of state to terminate and change of state is an opportunity for bugs.

let mutable i = 0
while(i < 3) do
    printfn "Hello World"
    i <- i + 1
for i = 1 to 10 do
    printfn "%A" i
// This type of loop is quite safe
let arr = ["One";"Two";"Three"]
for t in arr do
    printfn "%A" t

//Shorter version
for t in ["One";"Two";"Three"] do printfn "%A" t


Pattern matching

Pattern matching should be used in all cases where a simple if is not enough. _ is a wildcard and matches anything

// Special case as look up table
let binDigit = function
               | "0" -> Some 0
               | "1" -> Some 1
               | _   -> None
                        
// General syntax
let fTest fn = match fn with
               | None    -> "File not found"
               | Some(n) -> "File '%A' was found" n

Arrays

Arrays are fast as long as they are fixed length.

Creating arrays
let a = [||]                              // [||] (Empty array)
let a = [|2..7|]                          // [|2; 3; 4; 5; 6; 7|]
let a = [|2..2..7|]                       // [|2; 4; 6|]
let a : int [] = Array.zeroCreate 3       // [|0; 0; 0|]
let a = Array.init 5 (fun i -> i * i)     // [|0; 1; 4; 9; 16|]
let a = [|for i = 1 to 3 do yield i * 3|] // [|3; 6; 9|]
Slicing arrays
let a = [|1;2;3;4|]
let b = a.[2]       // This will set b to 3
let c = a.[1..2]    // This will set c to [|2;3|]
let d = a.[..2]     // This will set d to [|1;2;3|]
let e = a.[1..]     // This will set e to [|2;3;4|]

Lists

Lists are fast and memory efficient when items are added or removed from the start. Random access and operations at the end of the list are slow.

Creating lists works the same as creating arrays.
let a = []
let a = [1;2;3]
...
Adding one element to the front of a list using the Cons operator.
This is extremely efficient since the new element just links to the original list.
If you need to add to the end of the list you can reverse the list after it is completed.
let a = [1;2;3]
let b = 0 :: a      // b = [0;1,2,3]
Joining two lists using the Append operator.
let a = [1;2;3]
let b = [4;5;6]
let c = a @ b     // c = [1;2;3;4;5;6]
Always use the cons operator when possible.

Sequences

A sequence is an ordered sequence of items like a list. The main difference is that a sequence does not have to exist in memory, it can be computed on the fly and can be infinite.

Creating sequences works mostly the same as creating lists.
The sequence expression can be recursive using the yield! operator.
let a = seq{1..3}  // a = seq [1; 2; 3]
...

Processing data in a functional way

The seasiest method is to run a function on every item of a colletion of items to create a new collection.

let a = [1..5]           // The list to process
let mul2 n = n * 2       // Function that will be run on each item in the list
let b = List.map mul2 a  // Mapping the input list through the function mul2 to an output list
                         // The operation is [1;2;3;4;5] -> mul2 -> [2;4;6;8;10]
Using the fun keyword we can create an anonymous function in place
This is helpful if the function is simple and only is required once.
let b = List.map (fun n -> n * 2) a 


The other method is to use a recursive function.

let mul2 l = 
    let rec loop listIn listOut =
        match listIn with
        | []   -> listOut
        | h::t -> loop t (h * 2 :: listOut)
    List.rev (loop l [])

mul2 [1..5] // Gives [2;4;6;8;10]