{ | |||||
"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) |