| { | |||||
| "FSharp.suggestGitignore": false | |||||
| } |
| open System.Net | |||||
| open System | |||||
| open System.IO | |||||
| let fetchUrl cb url = | |||||
| let req = WebRequest.Create(Uri(url)) | |||||
| use resp = req.GetResponse() | |||||
| use stream = resp.GetResponseStream() | |||||
| use reader = new IO.StreamReader(stream) | |||||
| cb reader url | |||||
| let myCb (reader:IO.StreamReader) url = | |||||
| let html = reader.ReadToEnd() | |||||
| let html1000 = html.Substring(0,1000) | |||||
| printfn "Downloaded %s. First 1000 is %s" url html1000 | |||||
| html | |||||
| // let blog = fetchUrl myCb "https://blog.etopiei.com" | |||||
| // This could also be written `point free` but I like the explicitness | |||||
| let generalPageDownload url = fetchUrl myCb url | |||||
| generalPageDownload "https://google.com" | |||||
| generalPageDownload "https://etopiei.com" |
| let myInt = 5 | |||||
| let myFloat = 3.14 | |||||
| let myString = "Hello" | |||||
| let twoToFive = [2;3;4;5] | |||||
| let oneToFive = 1 :: twoToFive // New first element | |||||
| let zeroToFive = [0;1] @ twoToFive // Concatenation | |||||
| let square x = x * x | |||||
| square 3 | |||||
| let add x y = x + y | |||||
| add 2 3 | |||||
| let evens list = | |||||
| let isEven x = x % 2 = 0 // Inline function | |||||
| List.filter isEven list // Basic libary function | |||||
| evens oneToFive | |||||
| let sumOfQuaresTo100 = | |||||
| List.sum ( List.map square [1..100] ) | |||||
| let sumOfSquaresTo100piped = | |||||
| [1..100] |> List.map square |> List.sum | |||||
| let sumOfSquaresTo100WithFun = | |||||
| [1..100] |> List.map (fun x->x*x) |> List.sum // `fun` is like a lambda | |||||
| // F# Functions return implicitly | |||||
| let simplePatternMatch = | |||||
| let x = "a" | |||||
| match x with | |||||
| | "a" -> printfn "x is a" | |||||
| | "b" -> printfn "x is b" | |||||
| | _ -> printfn "x is something else" | |||||
| let validValue = Some(99) | |||||
| let invalidValue = None | |||||
| let optionPatternMatch input = | |||||
| match input with | |||||
| | Some i -> printfn "Input is an int=%d" i // similar to c format strings | |||||
| | None -> printfn "Input missing" | |||||
| optionPatternMatch validValue | |||||
| optionPatternMatch invalidValue | |||||
| // Stuff with data types | |||||
| let twoTuple = 1,2 | |||||
| let threeTuple = "a",2,true | |||||
| type Person = {First:string; Last:string} // Record types have named fields | |||||
| let person1 = {First="john"; Last="roberts"} | |||||
| type Temp = | |||||
| | DegreesC of float | |||||
| | DegreesF of float | |||||
| let temp = DegreesF 98.6 | |||||
| type Employee = | |||||
| | Worker of Person | |||||
| | Manager of Employee list | |||||
| let worker = Worker person1 | |||||
| // Printing stuff out | |||||
| printfn "Printing an int %i, a float %f, a bool %b" 1 2.0 true | |||||
| printfn "A string %s, and something generic %A" "hello" [1;2;3;4] | |||||
| // You can also print complex types that have been created | |||||
| printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A" | |||||
| twoTuple person1 temp worker |
| let printInt = printfn "%d" | |||||
| let product n = | |||||
| let initialValue = 1 | |||||
| let action productSoFar x = productSoFar * x | |||||
| [1..n] |> List.fold action initialValue | |||||
| printInt (product 10) | |||||
| let sumOfOdds n = | |||||
| let initialValue = 0 | |||||
| let action sumSoFar x = if x % 2 = 0 then sumSoFar else sumSoFar + x | |||||
| [1..n] |> List.fold action initialValue | |||||
| printInt (sumOfOdds 10) | |||||
| let alternatingSum n = | |||||
| let initialValue = (true, 0) | |||||
| let action (isNeg, sumSoFar) x = if isNeg then (false, sumSoFar - x) else (true, sumSoFar + x) | |||||
| [1..n] |> List.fold action initialValue |> snd // `snd` means the second in a tuple | |||||
| printInt (alternatingSum 100) | |||||
| // Now we can factor out the commonality and re-write these functions like so: | |||||
| let iterAct ini act n = | |||||
| [1..n] |> List.fold act ini | |||||
| let product2 = iterAct 1 (fun x y -> x * y) | |||||
| printInt (product2 10) | |||||
| let sumOfOdds2 = iterAct 0 (fun x y -> if y % 2 = 0 then x else x + y) | |||||
| printInt (sumOfOdds2 10) | |||||
| let rec quicksort list = | |||||
| match list with | |||||
| | [] -> [] // Empty list | |||||
| | firstEl::tail -> | |||||
| let smallerEls = | |||||
| tail | |||||
| |> List.filter (fun e -> e < firstEl) | |||||
| |> quicksort | |||||
| let larger = | |||||
| tail | |||||
| |> List.filter (fun e -> e >= firstEl) | |||||
| |> quicksort | |||||
| smallerEls @ [firstEl] @ larger | |||||
| printfn "%A" (quicksort [1;5;23;18;9;1;3]) |
| type IntAndBool = {intPart: int; boolPart: bool } // This is a `product` type. i.e. It is made from other simple types | |||||
| let x = {intPart=1; boolPart=false} // This is data of type `IntAndBool` | |||||
| type IntOrBool = | |||||
| | IntChoice of int | |||||
| | BoolChoice of bool // This is a `sum` type, i.e. it is made up of either simple type specified here | |||||
| let y = IntChoice 42 | |||||
| let z = BoolChoice true | |||||
| // We can use types to achieve similar control flows to that of imperative languages. | |||||
| // Here is code that is analagous to an if-then-else construct | |||||
| let booleanExpression = true | |||||
| match booleanExpression with | |||||
| | true -> printfn "true" // Do things for true | |||||
| | false -> printfn "false" // Do things for false | |||||
| // Notice that this is very concise syntax and gets to the core of what we want to do | |||||
| // Here's a 'switch' statement | |||||
| let aDigit = 3 | |||||
| match aDigit with | |||||
| | 1 -> printfn "1" // Do things for 1 | |||||
| | 2 -> printfn "2" // Do things for 2 | |||||
| | _ -> printfn "Something else" // like 'default' in switch | |||||
| // For loops are replaced with recursion | |||||
| let aList = [1;2;3] | |||||
| let rec printList list = | |||||
| match list with | |||||
| | [] -> [] // Empty | |||||
| | head::tail -> // Process first element, then recurse | |||||
| printfn "%d" head | |||||
| printList tail | |||||
| printList aList | |||||
| // To do something like polymorphism | |||||
| // we create `sum types` | |||||
| type Shape = | |||||
| | Circle of radius:int | |||||
| | Rectangle of height:int * width:int // Note tuples defined with '*' | |||||
| | Point of x:int * y:int | |||||
| | Polygon of pointList:(int * int) list | |||||
| let draw shape = | |||||
| match shape with | |||||
| | Circle radius -> printfn "The circle has radius: %d" radius | |||||
| | Rectangle (height, width) -> printfn "Height is %d" height // etc.. | |||||
| | Polygon points -> points |> List.iter (printfn "%A") // you get it | |||||
| | _ -> printfn "I'm done" | |||||
| // Then you can do things with lists like: | |||||
| // shapes |> List.iter draw (imagine shapes is a list of shapes) |