Skip to content

Instantly share code, notes, and snippets.

@colelawrence
Created March 28, 2017 17:19
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 colelawrence/1d1c7fb9a669ca2dfd545445e5599449 to your computer and use it in GitHub Desktop.
Save colelawrence/1d1c7fb9a669ca2dfd545445e5599449 to your computer and use it in GitHub Desktop.
Practicing F-Sharp, very similar to Elixir concepts.
#load "GetStarted1.fs"
open GetStarted1
// https://fsharpforfunandprofit.com/posts/control-flow-expressions/
// https://docs.microsoft.com/en-us/dotnet/articles/fsharp/tour#pipelines-and-composition
// Pattern matching examples
let a,b = 1,2
type Person = {First:string; Last:string}
let alice = {First="Alice"; Last="Doe"}
let {First=first} = alice
//
// `use` is assoc with System.IDisposible compatible values.
// After a use statement goes out of scope, the resource is disposed of.
// This is brilliant, as it allows us to differentiate between long living and shared resources and to die resources with a single keyword difference.
// create a new object that implements IDisposable
let makeResource name =
{ new System.IDisposable
with member this.Dispose() = printfn "%s disposed" name }
// let returnInvalidResource name =
// use myResource = makeResource name
// myResource // don't do this!
// // test
// let resource = returnInvalidResource "hello"
//
// As always, you can force a non-unit result to be discarded by piping the results into “ignore”.
do ( 1+1 |> ignore )
type Lang =
| En
| Es
| Fr
let GetGreeting lang =
match lang with
| En ->
"Hello"
| Es ->
"Hola"
| Fr ->
"Bonjour"
// Define your library scripting code here
let Greet prefix = GetGreeting >> printfn "%s: %s, %s!" prefix
let GreetEnglish = Greet "Hey" En
// Similarly written to Java / C#
let primesUpToVerbose n =
// create a recursive intermediate function
let rec sieve listOfNumbers =
match listOfNumbers with
| [] -> []
| primeP::sievedNumbersBiggerThanP->
let sievedNumbersNotDivisibleByP =
sievedNumbersBiggerThanP
|> List.filter (fun i-> i % primeP > 0)
//recursive part
let newPrimes = sieve sievedNumbersNotDivisibleByP
primeP :: newPrimes
// use the sieve
let listOfNumbers = [2..n]
sieve listOfNumbers // return
// Here is the same implementation, with terser, idiomatic names and more compact code:
let primesUpTo n =
let rec sieve l =
match l with
| [] -> []
| p::xs ->
p :: sieve [for x in xs do if (x % p) > 0 then yield x]
[2..n] |> sieve
// The common naming conventions are as follows:
// - "a", "b", "c" etc., are types
// - "f", "g", "h" etc., are functions
// - "x", "y", "z" etc., are arguments to the functions
// - Lists are indicated by adding an "s" suffix, so that
// "xs" is a list of x's, "fs" is a list of functions,
// and so on. It is extremely common to see "x::xs"
// meaning the head (first element) and tail (the
// remaining elements) of a list.
// - "_" is used whenever you don’t care about the value.
// So "x::_" means that you don't care about the rest
// of the list, and "let f _ = something" means you
// don't care about the argument to f.
// Avoiding If-then-else
// bad
let f1 x =
if x = 1
then "a"
else "b"
// not much better
let f2 x =
match x=1 with
| true -> "a"
| false -> "b"
// best (direct matching)
let f3 x =
match x with
| 1 -> "a"
| _ -> "b"
// Part of the reason why direct matching is better
// is that the equality test throws away useful
// information that you often need to retrieve again.
// The first implementation does a test for empty and
// then a second operation to get the first element.
// A much better approach is to match and extract
// the element in one single step, as shown in the
// second implementation.
// bad
let fa list =
if List.isEmpty list
then printfn "is empty"
else printfn "first element is %s" (List.head list)
// much better
let fb list =
match list with
| [] -> printfn "is empty"
| x::_ -> printfn "first element is %s" x
// Refactoring complex matching with `when`
// bad
let fc list =
if List.isEmpty list
then printfn "is empty"
elif (List.head list) > 0
then printfn "first element is > 0"
else printfn "first element is <= 0"
// much better
let fd list =
match list with
| [] -> printfn "is empty"
| x::_ when x > 0 -> printfn "first element is > 0"
| x::_ -> printfn "first element is <= 0"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment