Skip to content

Instantly share code, notes, and snippets.

@danyaljj
Created June 26, 2015 00:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danyaljj/8a1c3e66c6ead4f508fa to your computer and use it in GitHub Desktop.
Save danyaljj/8a1c3e66c6ead4f508fa to your computer and use it in GitHub Desktop.
Fsharp gist
// Random notes on F#
// Daniel Khashabi, June 2014
// References :
// http://learnxinyminutes.com/docs/fsharp/
// http://www.fincher.org/tips/Languages/fsharp.shtml
// http://fsharpforfunandprofit.com/
// http://en.wikibooks.org/wiki/F_Sharp_Programming
open System
(*This is a multiline comment
And this is another line *)
// this is a single line comment
// this is a documentation comment
// alt + enter runs the code in the interactive
// to reset the interactive :
// --> right click on the interactive
// --> reset interactive
// Now : C# directives
// Referencing (loading dynamicaly) given DLL file
// Can be used only in f# scripts : .fsx or fsscript
// #r "file.dll"
// Adding the given search pat for the references DLLs
// #l "path"
// Loading a csharp file
// #load "file.fs"
// Toggle timing on or off
// #time ["on"|"off"]
// Exiting from the program :
// #quit
// set the compiler warning level to light mode --> hash light
// #light
// pause at the end of the program
// Console.ReadKey() |> ignore
// or
// System.Console.ReadKey(true)
let int1 = 5
let float = 4.2
let string1 = "ahsan! "
printfn "Integer = %i" int1
printfn "Integer = %f" float
printfn "String = %s" string1
// asignments altogether
let dog, cat = "bark", "meaw"
// all variables are immutable by default
// so we can't reassign them
// so this is wrong : dog <- "bark2"
// also this is not assignment, but just comparison : dog = "bark2"
// we define mutable variables this way :
let mutable total = 100
printfn "%i" total
total <- 200
printfn "%i" total
// one can specify the type of the value by adding a suffix to it
let a = 0I // --> big num --> arbitrary precision
let b = 0u // --> uint32 == uint
let c = 2.45f // --> float
// one needs to be careful about overflow in F#
// it happends quietly
let mutable d = System.Int32.MaxValue // note that Int ~ Int32
d <- d + 1 // overflow without any warning or error
// the 'unit' type is equivalent to 'null' in java and C# (no object)
let x = ()
// one can assign the values in different bases (why it doesn't work?!)
// let hexNumber = 0x
// let octalNumber = 0o
// let binaryNumber = 0b // or 0B
// boolean operators: && || not
// one can access elements of an string just like arrays using .[]
let aString = "This is a string!"
printfn "A character from this string = %c" aString.[0]
// or you can just embede the end-of-line and whitespce characters in your assignment
let anotherStringWithNewLines = "This
has
multiple
new lines "
printfn "Value = %s" anotherStringWithNewLines
// we use @ for verbatim strings (in which we don't want to use escape characters )
// just like C#
let addresss = @"C:\home\daniel"
// if structure
// if is an expression and always returns a values
// if it doesn't have an else part, or just don't return a value, in that cases it returns 'unit' type
let evenOrOdd x =
if x % 2 = 0 then
printfn "even"
else
printfn "odd"
let getPrice size =
let price =
if size = "small" then 1.0
elif size = "medium" then 1.5
else 1.75
printfn "the price is %f" price
// note that all of the return types must be the same
// for example in the avove if the first return type cannot be 1 (instead of 1.0)
// looping : can be done explicitely but implicite is preferred
for i = 1 to 10 do
printfn "i = %d" i
for j = 10 downto 5 do
printfn "i = %d" j
let mutable xx = 0
while xx < 10 do
printfn "xx = %d" xx
xx <- xx + 1
// lists
let twoToFive = [2;3;4;5]
let oneToFive = 1::twoToFive // attaching one element
let zeroToFive = [0;1] @ twoToFive // concatenating two lists together
// an expression can act like a function :
let square x = x * x
printfn "square 3 is %i" (square 3)
let add x y = x + y
printfn "add 2 3 is %i" (add 2 3)
let nums = [1..4]
// using list with a loop
let sqr x = x * x
let sumOfSquaresI nums =
let mutable acc = 0
for x in nums do
acc <- acc + sqr x
acc
printfn "sumOfSquaresI nums = %d" (sumOfSquaresI nums)
// A better way using matching
let rec sumOfSquaresF nums =
match nums with
| [] -> 0
| h::t -> sqr h + sumOfSquaresF t
printfn "sumOfSquaresF nums = %d" (sumOfSquaresF nums)
// Much better way using pipeline
let sumOfSquares nums =
nums
|> Seq.map sqr
|> Seq.sum
printfn "sumOfSquares nums = %d" (sumOfSquares nums)
Console.ReadKey() |> ignore
// doing some more interesting stuff
let sampleList = [1..15]
let evens list =
let isEven x = x%2 = 0
List.filter isEven list
printfn "The list of evens = %A " (evens sampleList)
let sumOfSquaresTo100 =
List.sum ( List.map square [1..100])
// this is an implcitely defining a function using 'fun' keyword
// and mapping a list element by element with it
let sumOfSquaresTo100WithFun =
[1..100] |> List.map ( fun x -> x*x ) |> List.sum
// pattern matching
let simplePatternMatch =
let x = "a"
match x with
| "a" -> printfn "x is a "
| "b" -> printfn "x is b "
| _ -> printfn "x is something else ! "
// "discriminated union"s has structure similar to
// matching, using/defining types
// Some and None are some predefined types
let validValue = Some(99)
let invalidValue = None
let optionPatternMatch input =
match input with
| Some i -> printfn "input is %d " i
| None -> printfn "input is missing! "
optionPatternMatch validValue
optionPatternMatch invalidValue
printfn "printing int %i, float %f boolean %b" 1 2.0 true
printfn "printing %s and something generic %A " "asjih adam! " [1;2;3;4]
module FunctionExamples =
let add x y = x + y
printfn "1 + 2 = %i " (add 1 2 )
let add42 = add 42
printfn "42 + 1 = %i" ( add42 1 )
let add1 = add 1
let add2 = add 2
let add3 = add1 >> add2 // composition : adding functions
printfn "3 + 7 = %i" (add3 7)
[1..10] |> List.map add3 |> printfn "new list is %A"
let add6 = [add1; add2; add3] |> List.reduce(>>) // composition of al functions
let d = add6 7
printfn "1+2+3+7 = %i" d
// A quick summary :
// Lists : immutable
// Arrays: mutable
// Sequences : immutable, lazy
// Sets: immutable
// Maps: immutable
// list and collection
module ListExamples =
let list1 = ["a"; "b"]
let list2 = "c" :: list1 // :: is prepending
let list3 = list1 @ list2 // @ is concatenating ! --> they are different
// let list4 = list1 :: list2 --> You can't do this !
let squares = [for i in 1..10 do yield i*i]
// prime number :
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
// note the usage of 'first' and 'second'
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 []
let rec sum aList =
match aList with
| [] -> 0
| x::xs -> x + sum xs
printfn "sum of all elements inside the list = %d" (sum [1..10] )
// standard library functions
// generating random numbers
open System
let ran = new Random()
let x = ran.Next() // a big random integer
let y = ran.NextDouble() // a random real number in [0, 1]
// getting a big integer value
let maxVal = System.Int32.MaxValue
// maping all elements
let add3 x = x + 3
printfn "summing all elements of %A with 3 %A" ([1..10]) ([1..10] |> List.map add3 )
// filter : it filters anything which is labeled zero
let even x = x % 2 = 0
printfn "the list of the filtered elements in %A is = %A" [1..10] ([1..10] |> List.filter even )
// arrays
// array: represented with : [| |]
let fibo = Array.create 20 1
for i in 2..19 do
fibo.[i] <- fibo.[i-1] + fibo.[i-2]
printfn "%A" fibo
for i in 0 .. 19 do
printfn "%i " fibo.[i]
printfn "%s" " "
for i in 19 .. -1 .. 0 do
printfn "%i " fibo.[i]
printfn "%s" " "
// replacing digits with some other digit
printfn "Type a number = "
let xx:int32 = int32 (Console.ReadLine())
let d1:int32 = int32 (Console.ReadLine())
let d2:int32 = int32 (Console.ReadLine())
let rec swap n d1 d2 =
if n = 0 then 0
else
if n % 10 = d1 then d2 + 10 * swap(n/10) d1 d2
else n%10 + 10 * swap(n/10) d1 d2
printfn "%i" (swap xx d1 d2)
module ArrayExamples =
let array1 = [| "a"; "b" |] /// arrays use brackets with bar
let first = array1.[0] // indexed access with dot
// note about the
let arrayMatcher aList =
match aList with
| [| |] -> printfn "the array is empty ! "
| [| first |] -> printfn "has one element %A " first
| [| first; second |] -> printfn "the array is %A and %A" first second
| _ -> printfn "the array has more than two elements "
arrayMatcher [| 1;2;3;4 |]
// standard functions just for arrays
// Array.iter : runs the same function on each values of the array
[| 1..10|]
|> Array.map (fun i -> i+3)
|> Array.filter (fun i -> i%2 = 0)
|> Array.iter (printfn "value is %i")
// sequences
// unlike lists, sequences ae 'lazy', i.e. their elements are calculated
// they are needed. This can be useful when you want to create datastructre
// of size very big, since you don't need to use all elemnts, whenever you
// want to call one element
module SequenceExamples =
let seqExample = seq { 1 .. 10 }
let seqExample2 = seq { 1 .. 2 .. 10 }
let seqExample3 = seq { 10 .. -1 .. 1 }
let seqExample4 = seq { for a in 1 .. 10 do yield a, a*a, a*a*a }
let seqExample5 = seq {yield 1; yield 2} // --> yield adds one element
// like lists, elements, sequences should have
// elements of the same type. For example
// the following doesn't work
//let seq1 = seq {yield 1; yield "a" }
// yield adds an element
let seqExample6 = seq {
yield 1; yield 2 // yield adds one element
yield! [5..10] // yield! adds a whole elements
yield! seq{
for i in 1..10 do
if i%2 = 0 then yield i }}
// modules for sequences
// convertion to list
let convertedToList = seqExample6 |> Seq.toList
// appending two sequences
let test = Seq.append( seq{1 .. 3} ) ( seq{4 .. 7} )
// choose: filtering and mapping to another sequences
// what?!
let filterExample = seq { for nm in [Some("Ali"); None; Some("Vali"); Some("Sandali")]
|> Seq.choose id -> nm.Length }
// distinct : keeps the distinct elements
let distincSeq = Seq.distinct ( seq[1;1;1;4;5;5;3;3] )
// determine if en element exists in a sequence
let pattern x = x = 2
let existsValue = Seq.exists pattern (seq{3..9})
// filter
let filteredSeq = Seq.filter ( fun x -> if x%2=0 then true else false ) (seq{0..9})
// fold: folding with some pattern
let sumSeq seq1 = Seq.fold(fun acc elem -> acc + elem ) 0 seq1
Seq.init 10 (fun index -> index * index ) |> sumSeq |> printfn "Sume of the elements is %d"
// unfold: creating sequence with some pattern
let fib = Seq.unfold( fun( fst, snd ) ->
Some( fst + snd, (snd, fst + snd))) (0,1)
// take: up to the nth element :
let fib10 = fib |> Seq.take 10 |> Seq.toList
printf "first 10 fibs are %A" fib10
// nth element :
let nThElement = Seq.nth 3 (seq {for n in 2..9 do yield n})
// everything is ummutable by default: except some stuff outside the standard F# like arrays
// tuples :
// tuples: comma to create tuples :
let twoTuple = 1,2
let threeTuple = "a", 2, true
// unpacking the tuple
let x, y = twoTuple
// Records :
// have typed fields
type Person = {First:string; Last:string}
let person1 = {First="John"; Last="Doe"}
type ComplexNumber = {Real: float; Imaginary: float}
let aComplexNumber = {Real = 1.1; Imaginary = 1.2}
let {First=first} = person1 // only sets "John"
let {Real=aNum1; Imaginary=aNum2} = aComplexNumber // only sets "John"
// discriminated union:
// union types aka variants --> only one option is true
type Temp =
| DegreesC of float
| DegreesF of float
let temp1 = DegreesF 98.6
let temp2 = DegreesC 37.0
let printTemp = function
| DegreesC t -> printfn "%f degC " t
| DegreesF t -> printfn "%f degF " t
printTemp temp1
printTemp temp2
// I can define the types recursively
type Employee =
| Worker of Person
| Manager of Employee list
let jdoe = {First = "John"; Last="Doe"}
let worker = Worker jdoe
type EmailAddress =
| ValidEmailAAddress of string
| InvalidEmailAddress of string
let trySendEmail email =
match email with // pattern matching
| ValidEmailAAddress address -> () // send
| InvalidEmailAddress address -> () // do not send
type CartItem = {ProductionCode : string; Qty: int}
type Payment = Payment of float
type ActiveCartData = {UnpaidItems : CartItem list}
type PaidCartData = {PaidItems: CartItem list; Payment: Payment}
type ShoppingCart =
| EmptyCart // no data
| ActiveCart of ActiveCartData
| PaidCart of PaidCartData
// Core types
// -> Immutable
// -> Equaltiy and comparison
// -> Serialization
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 hight, based on the first element) %A"
List.max hand |> printfn "max value is %A"
List.min hand |> printfn "min value is %A"
// active patterns
module ActivePatternExamples =
// special types of pattern matching for types --> "active patterns"
let(|Digit|Letter|Whitespace|Other|) ch =
if System.Char.IsDigit(ch) then Digit
else if System.Char.IsLetter(ch) then Letter
else if System.Char.IsWhiteSpace(ch) then Whitespace
else Other
let printChar ch =
match ch with
| Digit -> printfn "%c is a Digit " ch
| Letter -> printfn "%c is a Letter " ch
| Whitespace -> printfn "%c is a Whitespace " ch
| _ -> printfn "%c is something else " ch
// print the list
['a'; 'b'; '1'; ' '; '-'; 'c'] |> List.iter printChar
// Example: fizbuzz
let(|MultOf3|_|) i = if i % 3 = 0 then Some MultOf3 else None
let(|MultOf5|_|) i = if i % 5 = 0 then Some MultOf5 else None
let fizzBuzz i =
match i with
| MultOf3 & MultOf5 -> printf "FizzBuzz, "
| MultOf3 -> printf "Fuzz, "
| MultOf5 -> printf "Buzz, "
| _ -> printf "%i, " i
[1..20 ] |> List.iter fizzBuzz
module AlgorithmExamples =
// sum of squares
let sumOfSquares n = [1..n] |> List.map square |> List.sum
// test
sumOfSquares 100 |> printfn "sum of squares = %A"
// sorting :
let rec sort list =
match list with
|[] -> []
| firstElem::otherElements ->
let smallerElements =
otherElements
|> List.filter (fun e -> e < firstElem)
|> sort
let largerElements =
otherElements
|> List.filter (fun e -> e >= firstElem)
|> sort
List.concat [smallerElements; [firstElem]; largerElements]
sort [1; 5; 24; 15; 18; 4; 1; 5] |> printfn "Sorted = %A "
// .Net functions
module DotNetCompatibilityExampels =
// work with the existing libraries
let( i1success, i1) = System.UInt32.TryParse("123");
if i1success then printfn "parsed as %i" i1 else printfn "parse failed"
// create an objecti that implements IDisposable
let makeResource name =
{ new System.IDisposable
with member this.Dispose() = printfn "%s disposed " name }
let useAndDisposeResources =
use r1 = makeResource "first resource "
printfn "using first resource "
for i in [1..3] do
let resourceName = sprintf "\tubber resiyrce %d" i
use temp = makeResource resourceName
printfn "\tdo something with %s" resourceName
use r2 = makeResource "second resource "
printfn "done! "
// object oriented programming
// using generic type
type IEnumerator<'a> =
abstract member Current : 'a
abstract MoveNext : unit -> bool
// abstract base class with virtual methods
[<AbstractClass>]
type Shape() =
// readonly properties
abstract member Width : int with get
abstract member Height : int with get
// non-virtual member
member this.BoundingArea = this.Height * this.Width
// virtual method with base implementation
abstract member Print : unit -> unit
default this.Print () = printfn "I am a shape "
(* Why this doesn't work?! :(
// concrete ckass --> inherits from base class
type Rectangle(x:int, y:int) =
inherit Shape()
override this.Width() = x
override this.Height() = y
override this.Print() = printfn "I'm a Rectangle"
// test
let r = Rectangle(2,3)
printfn "The width is %i " r.Width
printfn "The area is %i" r.BoundingArea
r.Print()
*)
// extension methods : extending the existing classes with extension metions
type System.String with
member this.StartsWith = this.StartsWith "A"
// events
type MyButton() =
let clickEvent = new Event<_>()
[<CLIEvent>]
member this.OnClick = clickEvent.Publish
member this.TestEvent(arg) = clickEvent.Trigger(this, arg)
let myButton = new MyButton()
myButton.OnClick.Add(fun(sender, arg)-> printfn "CLick event with arg = %s" arg )
myButton.TestEvent("Hello World ! ")
// some more OO programming
// a class for customer
type CurtomerNamer(firstName, middleName, lastName ) =
member this.FirstName = firstName
// with get() = firstName1
// and set(value) = firstName1 <- value
member this.MiddleName = middleName
member this.LastName = lastName
member this.AppendTheNames = this.FirstName + this.LastName
member this.DesiredName x =
if x = "first" then
this.FirstName
elif x = "second" then
this.LastName
else
""
let me = new CurtomerNamer("Daniel", "", "Khashabi")
printfn "me.AppendTheNames = %s" me.AppendTheNames
printfn "me.AppendTheNames = %s" ( me.DesiredName "first" )
// one can specify the types in the constructor
(*
type CurtomerNamer(firstName:string, middleName:string, lastName:string ) =
member this.FirstName = firstName
member this.MiddleName = middleName
member this.LastName = lastName
*)
// if we want to send tuple to the constructor we need to annotate it explicitely :
type nonTupledConstructor (x:int, y:int) =
do printfn "x=%i y=%i" x y
type tupledConstructor (tuple:int * int) =
let x, y = tuple
do printfn "x=%i y=%i" x y
let myNTC = new nonTupledConstructor(1,2)
let myTC = new tupledConstructor(1,2)
System.Console.ReadKey() |> ignore
(*
[<EntryPoint>]
let main(args : string[]) =
0
*)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment