Created
April 17, 2014 21:22
-
-
Save rranelli/11012392 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (* Fsharp files must contain a module definition, which is equivalent to a namespace *) | |
| module FsharpHighlights | |
| #light | |
| (* The open statement is equivalent to c#'s using and vb's imports *) | |
| open System | |
| (* Functions are first class citizens ;D *) | |
| let square x = x * x | |
| let numbers x = [1..x] | |
| (* composition can be made using the pipeArrow operator *) | |
| let squares x = x |> numbers |> List.map square | |
| (* you can also compose functions using the usual pattern *) | |
| let squares2 x = List.map square (numbers x) | |
| (* sequences are nice, just like lists but lazily evaluated *) | |
| let seq = {1..10} | |
| (* you can use pattern matching in such a nice way ;D *) | |
| let (x,y) = (1,2) | |
| (* records are also quite nice, but you have to define them first as a type *) | |
| type coord = { X : float; Y : float } | |
| let myRecord = {X = 1.0; Y = 2.0} | |
| (* pattern matching everywere. *) | |
| let myHead :: theTail = [1; 2; 3; 4] // Note the compiler warning for non-exaustive pattern matching | |
| (* function definitions are made using let expressions. This makes functions even less special *) | |
| let rec facto = function | |
| | 0 -> 1 | |
| | n -> n * facto (n - 1) | |
| (* List Comprehensions are AWESOME *) | |
| let listcomprehended = [for x in 1..10 do if x % 2 = 0 then yield facto x] | |
| (* the construct let (functionName) = function {| pattern -> expr}+ is equivalent to ml's and erlang's | |
| multiple function entrypoints *) | |
| let rec all_except = function | |
| | (_, []) -> [] | |
| | (s1, head :: tail) -> if head = s1 | |
| then tail | |
| else head :: all_except (s1, tail) | |
| (* option types are nice *) | |
| let safediv x y = match y with | |
| | 0 -> None | |
| | _ -> Some(x / y) | |
| let safelyDivided = safediv 33 0;; | |
| (* you can also use currying for function definitions, | |
| but you lose the shorthand syntax of multiple entrypoints obviusly *) | |
| let rec all_except_curried x xlist = | |
| match xlist with | |
| | [] -> [] | |
| | head :: tail -> if head = x | |
| then tail | |
| else head :: tail | |
| (* Tagged unions do amor! *) | |
| type quadrant = Origin | I | II | III | IV | |
| (* pattern matching with records *) | |
| let getQuadrant = function | |
| | {X = 0.0 ; Y = 0.0; } -> Origin | |
| | item when item.X >= 0.0 && item.Y >= 0.0 -> I | |
| | item when item.X <= 0.0 && item.Y >= 0.0 -> II | |
| | item when item.X <= 0.0 && item.Y <= 0.0 -> III | |
| | item when item.X >= 0.0 && item.Y <= 0.0 -> IV | |
| | item -> raise (System.ArgumentException (String.Format ("Invalid Argument {0}", item))); // Exceptions are subtypes of it all | |
| (* Tagged/Discriminated unions can be used nicely the same way value objects are used *) | |
| type expr = Add of expr * expr | Const of int | Mult of expr * expr | Var of string | |
| type switchstate = On | Off | Adjustable of float | |
| let toggle = function | |
| | On -> Off | |
| | Off -> On | |
| | Adjustable brightness -> | |
| let pivot = 0.5 in if brightness <= pivot | |
| then Adjustable (brightness + pivot) | |
| else Adjustable (brightness - pivot) | |
| (* Tagged unions are the most beautifull trees you will ever see *) | |
| type 'a bintree = Leaf of 'a | Node of 'a bintree * 'a bintree | |
| let simpleTree = Node ( | |
| Leaf 1, | |
| Node ( | |
| Leaf 2, | |
| Node ( | |
| Node ( | |
| Leaf 4, | |
| Leaf 5 | |
| ), | |
| Leaf 3 | |
| ) | |
| ) | |
| ) | |
| let countLeaves tree = | |
| let rec loop sum = function | |
| | Leaf _ -> sum + 1 | |
| | Node (tree1, tree2) -> sum + (loop 0 tree1) + (loop 0 tree2) | |
| in | |
| loop 0 tree | |
| (* Propositional logic in a extremely concise manner *) | |
| type proposition = | |
| | True | |
| | False | |
| | Not of proposition | |
| | And of proposition * proposition | |
| | Or of proposition * proposition | |
| let rec eval = function | |
| | True -> true | |
| | False -> false | |
| | Not prop -> not (eval prop) | |
| | And (prop1, prop2) -> eval prop1 && eval prop2 | |
| | Or (prop1, prop2) -> eval prop1 || eval prop2 | |
| (* The distinction between classes and types now is kinda not existant. | |
| Fuction's as first class are THE thing *) | |
| type Account (number, holder) = | |
| let mutable amount = 0m | |
| member x.Number | |
| with get() = number | |
| member x.Holder | |
| with get() = holder | |
| member x.Amount | |
| with get() = amount | |
| member x.Deposit value = amount <- amount + value | |
| member x.Withdraw value = amount <- amount - value | |
| let homer = new Account (12345, "Homer") | |
| let marge = new Account (67890, "Marge") | |
| (* This function is shit. Returns Unit and sideeffects *) | |
| let transfer amount (source: Account) (target: Account) = | |
| source.Withdraw amount | |
| target.Deposit amount | |
| (* Inheritance and pattern matching for the win*) | |
| type Person (name) = | |
| member x.Name = name | |
| abstract Greet : unit -> unit | |
| default x.Greet() = printfn "Hi, I'm %s" x.Name | |
| type Student (name, studentId : int) = | |
| inherit Person (name) | |
| let mutable _GPA = 0.0 | |
| member x.StudentID = studentId | |
| member x.GPA | |
| with get() = _GPA | |
| and set value = _GPA <- value | |
| type Worker (name, employer) = | |
| inherit Person (name) | |
| let mutable _salary = 0.0 | |
| member x.Salary | |
| with get() = _salary | |
| and set value = _salary <- value | |
| member x.Employer = employer | |
| type Quebecois (name) = | |
| inherit Person (name) | |
| override x.Greet() = printfn "Bonjour, je m'apelle %s, eh" x.Name | |
| (*You can see that subtyping works wonders *) | |
| let astudent : Student = new Student ("myname", 1235) | |
| let handlesStuff (person : Person) = | |
| match person with | |
| | :? Student as student -> printfn "I am a student" | |
| | :? Quebecois as quebecois -> printfn "I be quebecois" | |
| | :? Worker as worker -> printfn "%A" worker.Name | |
| | _ -> printfn "I don't recognize type '%s'" (person.GetType().Name) | |
| let aperson = astudent | |
| let () = handlesStuff aperson | |
| let (somePerson, someStudent, someWorker) as triplz = | |
| ((new Person "Juliet"), (new Student ("Monique", 123456)), (new Worker ("Carla", "Awesome Hair Salon"))) | |
| // also, check that the trp parameter in tripleHandling must have type Person*Person*Person. No need to declare, but the compiler knows it all. | |
| let tripleHandling trp = | |
| match trp with | |
| | (x,y,z) -> handlesStuff x | |
| handlesStuff y | |
| handlesStuff z |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment