mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-24 10:01:38 +00:00
commit
47da17c37f
@ -6,11 +6,11 @@ author_url: http://fsharpforfunandprofit.com/
|
|||||||
|
|
||||||
F# is a general purpose functional/OO programming language. It's free and open source, and runs on Linux, Mac, Windows and more.
|
F# is a general purpose functional/OO programming language. It's free and open source, and runs on Linux, Mac, Windows and more.
|
||||||
|
|
||||||
It has a powerful type system that traps many errors at compile time, but it uses type inference so that it read more like a dynamic language.
|
It has a powerful type system that traps many errors at compile time, but it uses type inference so that it reads more like a dynamic language.
|
||||||
|
|
||||||
The syntax of F# is similar to Python:
|
The syntax of F# is different from C-style languages:
|
||||||
|
|
||||||
* Curly braces are not used to delimit blocks of code. Instead, indentation is used.
|
* Curly braces are not used to delimit blocks of code. Instead, indentation is used (like Python).
|
||||||
* Whitespace is used to separate parameters rather than commas.
|
* Whitespace is used to separate parameters rather than commas.
|
||||||
|
|
||||||
If you want to try out the code below, you can go to [tryfsharp.org](http://www.tryfsharp.org/Create) and paste it into an interactive REPL.
|
If you want to try out the code below, you can go to [tryfsharp.org](http://www.tryfsharp.org/Create) and paste it into an interactive REPL.
|
||||||
@ -123,7 +123,7 @@ printfn "A string %s, and something generic %A" "hello" [1;2;3;4]
|
|||||||
|
|
||||||
// Modules are used to group functions together
|
// Modules are used to group functions together
|
||||||
// Indentation is needed for each nested module.
|
// Indentation is needed for each nested module.
|
||||||
module Addition =
|
module FunctionExamples =
|
||||||
|
|
||||||
// define a simple adding function
|
// define a simple adding function
|
||||||
let add x y = x + y
|
let add x y = x + y
|
||||||
@ -132,12 +132,12 @@ module Addition =
|
|||||||
let a = add 1 2
|
let a = add 1 2
|
||||||
printfn "1+2 = %i" a
|
printfn "1+2 = %i" a
|
||||||
|
|
||||||
// partial application
|
// partial application to "bake in" parameters
|
||||||
let add42 = add 42
|
let add42 = add 42
|
||||||
let b = add42 1
|
let b = add42 1
|
||||||
printfn "42+1 = %i" b
|
printfn "42+1 = %i" b
|
||||||
|
|
||||||
// composition
|
// composition to combine functions
|
||||||
let add1 = add 1
|
let add1 = add 1
|
||||||
let add2 = add 2
|
let add2 = add 2
|
||||||
let add3 = add1 >> add2
|
let add3 = add1 >> add2
|
||||||
@ -153,30 +153,190 @@ module Addition =
|
|||||||
printfn "1+2+3+7 = %i" d
|
printfn "1+2+3+7 = %i" d
|
||||||
|
|
||||||
// ================================================
|
// ================================================
|
||||||
// Data Types
|
// Lists and collection
|
||||||
// ================================================
|
// ================================================
|
||||||
|
|
||||||
|
// There are three types of ordered collection:
|
||||||
|
// * Lists are most basic immutable collection.
|
||||||
|
// * Arrays are mutable and more efficient when needed.
|
||||||
|
// * Sequences are lazy and infinite (e.g. an enumerator).
|
||||||
|
//
|
||||||
|
// Other collections include immutable maps and sets
|
||||||
|
// plus all the standard .NET collections
|
||||||
|
|
||||||
|
module ListExamples =
|
||||||
|
|
||||||
|
// lists use square brackets
|
||||||
|
let list1 = ["a";"b"]
|
||||||
|
let list2 = "c" :: list1 // :: is prepending
|
||||||
|
let list3 = list1 @ list2 // @ is concat
|
||||||
|
|
||||||
|
// list comprehensions (aka generators)
|
||||||
|
let squares = [for i in 1..10 do yield i*i]
|
||||||
|
|
||||||
|
// prime number generator
|
||||||
|
let rec sieve = function
|
||||||
|
| (p::xs) -> p :: sieve [ for x in xs do if x % p > 0 then yield x ]
|
||||||
|
| [] -> []
|
||||||
|
let primes = sieve [2..50]
|
||||||
|
printfn "%A" primes
|
||||||
|
|
||||||
|
// pattern matching for lists
|
||||||
|
let listMatcher aList =
|
||||||
|
match aList with
|
||||||
|
| [] -> printfn "the list is empty"
|
||||||
|
| [first] -> printfn "the list has one element %A " first
|
||||||
|
| [first; second] -> printfn "list is %A and %A" first second
|
||||||
|
| _ -> printfn "the list has more than two elements"
|
||||||
|
|
||||||
|
listMatcher [1;2;3;4]
|
||||||
|
listMatcher [1;2]
|
||||||
|
listMatcher [1]
|
||||||
|
listMatcher []
|
||||||
|
|
||||||
|
// recursion using lists
|
||||||
|
let rec sum aList =
|
||||||
|
match aList with
|
||||||
|
| [] -> 0
|
||||||
|
| x::xs -> x + sum xs
|
||||||
|
sum [1..10]
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
// Standard library functions
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
|
// map
|
||||||
|
let add3 x = x + 3
|
||||||
|
[1..10] |> List.map add3
|
||||||
|
|
||||||
|
// filter
|
||||||
|
let even x = x % 2 = 0
|
||||||
|
[1..10] |> List.filter even
|
||||||
|
|
||||||
|
// many more -- see documentation
|
||||||
|
|
||||||
|
module ArrayExamples =
|
||||||
|
|
||||||
|
// arrays use square brackets with bar
|
||||||
|
let array1 = [| "a";"b" |]
|
||||||
|
let first = array1.[0] // indexed access using dot
|
||||||
|
|
||||||
|
// pattern matching for arrays is same as for lists
|
||||||
|
let arrayMatcher aList =
|
||||||
|
match aList with
|
||||||
|
| [| |] -> printfn "the array is empty"
|
||||||
|
| [| first |] -> printfn "the array has one element %A " first
|
||||||
|
| [| first; second |] -> printfn "array is %A and %A" first second
|
||||||
|
| _ -> printfn "the array has more than two elements"
|
||||||
|
|
||||||
|
arrayMatcher [| 1;2;3;4 |]
|
||||||
|
|
||||||
|
// Standard library functions just as for List
|
||||||
|
|
||||||
|
[| 1..10 |]
|
||||||
|
|> Array.map (fun i -> i+3)
|
||||||
|
|> Array.filter (fun i -> i%2 = 0)
|
||||||
|
|> Array.iter (printfn "value is %i. ")
|
||||||
|
|
||||||
|
|
||||||
|
module SequenceExamples =
|
||||||
|
|
||||||
|
// sequences use curly braces
|
||||||
|
let seq1 = seq { yield "a"; yield "b" }
|
||||||
|
|
||||||
|
// sequences can use yield and
|
||||||
|
// can contain subsequences
|
||||||
|
let strange = seq {
|
||||||
|
// "yield! adds one element
|
||||||
|
yield 1; yield 2;
|
||||||
|
|
||||||
|
// "yield!" adds a whole subsequence
|
||||||
|
yield! [5..10]
|
||||||
|
yield! seq {
|
||||||
|
for i in 1..10 do
|
||||||
|
if i%2 = 0 then yield i }}
|
||||||
|
// test
|
||||||
|
strange |> Seq.toList
|
||||||
|
|
||||||
|
|
||||||
|
// Sequences can be created using "unfold"
|
||||||
|
// Here's the fibonacci series
|
||||||
|
let fib = Seq.unfold (fun (fst,snd) ->
|
||||||
|
Some(fst + snd, (snd, fst + snd))) (0,1)
|
||||||
|
|
||||||
|
// test
|
||||||
|
let fib10 = fib |> Seq.take 10 |> Seq.toList
|
||||||
|
printf "first 10 fibs are %A" fib10
|
||||||
|
|
||||||
|
|
||||||
|
// ================================================
|
||||||
|
// Data Types
|
||||||
|
// ================================================
|
||||||
|
|
||||||
module DataTypeExamples =
|
module DataTypeExamples =
|
||||||
|
|
||||||
// All data is immutable by default
|
// All data is immutable by default
|
||||||
|
|
||||||
// Tuples are quick 'n easy anonymous types
|
// Tuples are quick 'n easy anonymous types
|
||||||
|
// -- Use a comma to create a tuple
|
||||||
let twoTuple = 1,2
|
let twoTuple = 1,2
|
||||||
let threeTuple = "a",2,true
|
let threeTuple = "a",2,true
|
||||||
|
|
||||||
// Record types have named fields
|
// Pattern match to unpack
|
||||||
type Person = {First:string; Last:string}
|
let x,y = twoTuple //sets x=1 y=2
|
||||||
let person1 = {First="john"; Last="Doe"}
|
|
||||||
|
|
||||||
|
// ------------------------------------
|
||||||
|
// Record types have named fields
|
||||||
|
// ------------------------------------
|
||||||
|
|
||||||
|
// Use "type" with curly braces to define a record type
|
||||||
|
type Person = {First:string; Last:string}
|
||||||
|
|
||||||
|
// Use "let" with curly braces to create a record
|
||||||
|
let person1 = {First="John"; Last="Doe"}
|
||||||
|
|
||||||
|
// Pattern match to unpack
|
||||||
|
let {First=first} = person1 //sets first="john"
|
||||||
|
|
||||||
|
// ------------------------------------
|
||||||
// Union types (aka variants) have a set of choices
|
// Union types (aka variants) have a set of choices
|
||||||
// Only case can be valid at a time.
|
// Only case can be valid at a time.
|
||||||
|
// ------------------------------------
|
||||||
|
|
||||||
|
// Use "type" with bar/pipe to define a union type
|
||||||
type Temp =
|
type Temp =
|
||||||
| DegreesC of float
|
| DegreesC of float
|
||||||
| DegreesF of float
|
| DegreesF of float
|
||||||
|
|
||||||
|
// Use one of the cases to create one
|
||||||
let temp1 = DegreesF 98.6
|
let temp1 = DegreesF 98.6
|
||||||
let temp2 = DegreesC 37.0
|
let temp2 = DegreesC 37.0
|
||||||
|
|
||||||
|
// Pattern match on all cases to unpack
|
||||||
|
let printTemp = function
|
||||||
|
| DegreesC t -> printfn "%f degC" t
|
||||||
|
| DegreesF t -> printfn "%f degF" t
|
||||||
|
|
||||||
|
printTemp temp1
|
||||||
|
printTemp temp2
|
||||||
|
|
||||||
|
// ------------------------------------
|
||||||
|
// Recursive types
|
||||||
|
// ------------------------------------
|
||||||
|
|
||||||
|
// Types can be combined recursively in complex ways
|
||||||
|
// without having to create subclasses
|
||||||
|
type Employee =
|
||||||
|
| Worker of Person
|
||||||
|
| Manager of Employee list
|
||||||
|
|
||||||
|
let jdoe = {First="John";Last="Doe"}
|
||||||
|
let worker = Worker jdoe
|
||||||
|
|
||||||
|
// ------------------------------------
|
||||||
|
// Modelling with types
|
||||||
|
// ------------------------------------
|
||||||
|
|
||||||
// Union types are great for modelling state without using flags
|
// Union types are great for modelling state without using flags
|
||||||
type EmailAddress =
|
type EmailAddress =
|
||||||
| ValidEmailAddress of string
|
| ValidEmailAddress of string
|
||||||
@ -187,15 +347,6 @@ module DataTypeExamples =
|
|||||||
| ValidEmailAddress address -> () // send
|
| ValidEmailAddress address -> () // send
|
||||||
| InvalidEmailAddress address -> () // dont send
|
| InvalidEmailAddress address -> () // dont send
|
||||||
|
|
||||||
// Types can be combined recursively in complex ways
|
|
||||||
// without having to create subclasses
|
|
||||||
type Employee =
|
|
||||||
| Worker of Person
|
|
||||||
| Manager of Employee list
|
|
||||||
|
|
||||||
let jdoe = {First="John";Last="Doe"}
|
|
||||||
let worker = Worker jdoe
|
|
||||||
|
|
||||||
// The combination of union types and record types together
|
// The combination of union types and record types together
|
||||||
// provide a great foundation for domain driven design.
|
// provide a great foundation for domain driven design.
|
||||||
// You can create hundreds of little types that accurately
|
// You can create hundreds of little types that accurately
|
||||||
@ -211,10 +362,35 @@ module DataTypeExamples =
|
|||||||
| ActiveCart of ActiveCartData
|
| ActiveCart of ActiveCartData
|
||||||
| PaidCart of PaidCartData
|
| PaidCart of PaidCartData
|
||||||
|
|
||||||
// All complex types have pretty printing built in for free
|
// ------------------------------------
|
||||||
|
// Built in behavior for types
|
||||||
|
// ------------------------------------
|
||||||
|
|
||||||
|
// Core types have useful "out-of-the-box" behavior, no coding needed.
|
||||||
|
// * Immutability
|
||||||
|
// * Pretty printing when debugging
|
||||||
|
// * Equality and comparison
|
||||||
|
// * Serialization
|
||||||
|
|
||||||
|
// Pretty printing using %A
|
||||||
printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A"
|
printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A"
|
||||||
twoTuple person1 temp1 worker
|
twoTuple person1 temp1 worker
|
||||||
|
|
||||||
|
// Equality and comparison built in.
|
||||||
|
// Here's an example with cards.
|
||||||
|
type Suit = Club | Diamond | Spade | Heart
|
||||||
|
type Rank = Two | Three | Four | Five | Six | Seven | Eight
|
||||||
|
| Nine | Ten | Jack | Queen | King | Ace
|
||||||
|
|
||||||
|
let hand = [ Club,Ace; Heart,Three; Heart,Ace;
|
||||||
|
Spade,Jack; Diamond,Two; Diamond,Ace ]
|
||||||
|
|
||||||
|
// sorting
|
||||||
|
List.sort hand |> printfn "sorted hand is (low to high) %A"
|
||||||
|
List.max hand |> printfn "high card is %A"
|
||||||
|
List.min hand |> printfn "low card is %A"
|
||||||
|
|
||||||
|
|
||||||
// ================================================
|
// ================================================
|
||||||
// Active patterns
|
// Active patterns
|
||||||
// ================================================
|
// ================================================
|
||||||
@ -224,6 +400,8 @@ module ActivePatternExamples =
|
|||||||
// F# has a special type of pattern matching called "active patterns"
|
// F# has a special type of pattern matching called "active patterns"
|
||||||
// where the pattern can be parsed or detected dynamically.
|
// where the pattern can be parsed or detected dynamically.
|
||||||
|
|
||||||
|
// "banana clips" are the syntax for active patterns
|
||||||
|
|
||||||
// for example, define an "active" pattern to match character types...
|
// for example, define an "active" pattern to match character types...
|
||||||
let (|Digit|Letter|Whitespace|Other|) ch =
|
let (|Digit|Letter|Whitespace|Other|) ch =
|
||||||
if System.Char.IsDigit(ch) then Digit
|
if System.Char.IsDigit(ch) then Digit
|
||||||
@ -242,6 +420,25 @@ module ActivePatternExamples =
|
|||||||
// print a list
|
// print a list
|
||||||
['a';'b';'1';' ';'-';'c'] |> List.iter printChar
|
['a';'b';'1';' ';'-';'c'] |> List.iter printChar
|
||||||
|
|
||||||
|
// -----------------------------------
|
||||||
|
// FizzBuzz using active patterns
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// You can create partial matching patterns as well
|
||||||
|
// Just use undercore in the defintion, and return Some if matched.
|
||||||
|
let (|MultOf3|_|) i = if i % 3 = 0 then Some MultOf3 else None
|
||||||
|
let (|MultOf5|_|) i = if i % 5 = 0 then Some MultOf5 else None
|
||||||
|
|
||||||
|
// the main function
|
||||||
|
let fizzBuzz i =
|
||||||
|
match i with
|
||||||
|
| MultOf3 & MultOf5 -> printf "FizzBuzz, "
|
||||||
|
| MultOf3 -> printf "Fizz, "
|
||||||
|
| MultOf5 -> printf "Buzz, "
|
||||||
|
| _ -> printf "%i, " i
|
||||||
|
|
||||||
|
// test
|
||||||
|
[1..20] |> List.iter fizzBuzz
|
||||||
|
|
||||||
// ================================================
|
// ================================================
|
||||||
// Conciseness
|
// Conciseness
|
||||||
@ -289,7 +486,7 @@ module AlgorithmExamples =
|
|||||||
|
|
||||||
module AsyncExample =
|
module AsyncExample =
|
||||||
|
|
||||||
// F# has some built-in features to help with async code
|
// F# has built-in features to help with async code
|
||||||
// without encountering the "pyramid of doom"
|
// without encountering the "pyramid of doom"
|
||||||
//
|
//
|
||||||
// The following example downloads a set of web pages in parallel.
|
// The following example downloads a set of web pages in parallel.
|
||||||
@ -301,10 +498,14 @@ module AsyncExample =
|
|||||||
|
|
||||||
// Fetch the contents of a URL asynchronously
|
// Fetch the contents of a URL asynchronously
|
||||||
let fetchUrlAsync url =
|
let fetchUrlAsync url =
|
||||||
async {
|
async { // "async" keyword and curly braces
|
||||||
|
// creates an "async" object
|
||||||
let req = WebRequest.Create(Uri(url))
|
let req = WebRequest.Create(Uri(url))
|
||||||
use! resp = req.AsyncGetResponse()
|
use! resp = req.AsyncGetResponse()
|
||||||
|
// use! is async assignment
|
||||||
use stream = resp.GetResponseStream()
|
use stream = resp.GetResponseStream()
|
||||||
|
// "use" triggers automatic close()
|
||||||
|
// on resource at end of scope
|
||||||
use reader = new IO.StreamReader(stream)
|
use reader = new IO.StreamReader(stream)
|
||||||
let html = reader.ReadToEnd()
|
let html = reader.ReadToEnd()
|
||||||
printfn "finished downloading %s" url
|
printfn "finished downloading %s" url
|
||||||
@ -360,7 +561,7 @@ module NetCompatibilityExamples =
|
|||||||
// F# is also a fully fledged OO language.
|
// F# is also a fully fledged OO language.
|
||||||
// It supports classes, inheritance, virtual methods, etc.
|
// It supports classes, inheritance, virtual methods, etc.
|
||||||
|
|
||||||
// interface
|
// interface with generic type
|
||||||
type IEnumerator<'a> =
|
type IEnumerator<'a> =
|
||||||
abstract member Current : 'a
|
abstract member Current : 'a
|
||||||
abstract MoveNext : unit -> bool
|
abstract MoveNext : unit -> bool
|
||||||
|
Loading…
Reference in New Issue
Block a user