// This is presented with permission from Scott Wlaschin, the original author. This has been slightly modified. // Single line comments use a double slash. (* Multi-line comments can be done this way (though double-slash is usually used). *)
// ======== "Variables" (but not really) ========== // The "let" keyword defines an (immutable) value let myInt = 5 let myFloat = 3.14 let myString = "hello"// note that no types needed
// ======== Lists ============ let twoToFive = [ 2; 3; 4; 5 ] // Square brackets create a list with // semicolon delimiters. let oneToFive = 1 :: twoToFive // :: creates list with new 1st element // The result is [1; 2; 3; 4; 5]
let zeroToFive = [0;1] @ twoToFive // @ concats two lists
// IMPORTANT: commas are never used as delimiters, only semicolons!
// ======== Functions ======== // The "let" keyword also defines a named function. let square x = x * x // Note that no parens are used. square 3// Now run the function. Again, no parens.
let add x y = x + y // don't use add (x,y)! It means something // completely different. add 23// Now run the function.
// to define a multiline function, just use indents. No semicolons needed. let evens list = let isEven x = x % 2 = 0// Define "isEven" as an inner ("nested") function List.filter isEven list // List.filter is a library function // with two parameters: a boolean function // and a list to work on evens oneToFive // Now run the function
// You can use parens to clarify precedence. In this example, // do "map" first, with two args, then do "sum" on the result. // Without the parens, "List.map" would be passed as an arg to List.sum let sumOfSquaresTo100 = List.sum (List.map square [ 1 .. 100 ])
// You can pipe the output of one operation to the next using "|>" // Here is the same sumOfSquares function written using pipes let sumOfSquaresTo100piped = [ 1 .. 100 ] |> List.map square |> List.sum // "square" was defined earlier
// you can define lambdas (anonymous functions) using the "fun" keyword let sumOfSquaresTo100withFun = [ 1 .. 100 ] |> List.map (fun x -> x * x) |> List.sum
// In F# returns are implicit -- no "return" needed. A function always // returns the value of the last expression used.
// ======== Pattern Matching ======== // Match..with.. is a supercharged case/switch statement. let x = "a" match x with | "a" -> printfn "x is a" | "b" -> printfn "x is b" | _ -> printfn "x is something else"// underscore matches anything
// Some(..) and None are roughly analogous to Nullable wrappers let validValue = Some(99) let invalidValue = None
// In this example, match..with matches the "Some" and the "None", // and also unpacks the value in the "Some" at the same time. let optionPatternMatch input = match input with | Some i -> printfn "input is an int=%d" i | None -> printfn "input is missing"
// Tuple types are pairs, triples, etc. Tuples use commas. let twoTuple = (1, 2) let threeTuple = ("a", 2, true)
// Record types have named fields. Semicolons are separators. typePerson= { First: string; Last: string }
let person1 = { First="John"; Last="Doe" } // You can also use new lines to elide the semiclon. let person2 = { First="Jane" Last="Doe" }
// Union types have choices. Vertical bars are separators. typeTemp= | DegreesC of float | DegreesF of float
let temp = DegreesF 98.6
// Types can be combined recursively in complex ways. // E.g. here is a union type that contains a list of the same type: typeEmployee= | Worker of Person | Manager of Employee list
let jdoe = { First="John"; Last="Doe" } let worker = Worker jdoe
// ========= Printing ========= // The printf/printfn functions are similar to the // Console.Write/WriteLine functions in C#. printfn "Printing an int %i, a float %f, a bool %b"12.0true printfn "A string %s, and something generic %A""hello" [ 1; 2; 3; 4 ]
// all complex types have pretty printing built in printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A" twoTuple person1 temp worker