Skip to content

Instantly share code, notes, and snippets.

@fabiomarreco
Created September 23, 2019 00:41
Show Gist options
  • Save fabiomarreco/3e40ae11364836a60e47ae1e76908e3b to your computer and use it in GitHub Desktop.
Save fabiomarreco/3e40ae11364836a60e47ae1e76908e3b to your computer and use it in GitHub Desktop.
1st exercises mentorship fsharp

F# Exercises

FizzbuzzImperative

module FizzbuzzImperative =
    let nums = [1..100]

    let fizzbuzzImperative i = 
        if i % 3 = 0 && i % 5 = 0 then
            printfn "fizzbuzz"
        elif i % 3 = 0 then
            printfn "fizz"
        elif i % 5 = 0 then
            printfn "buzz"
        else printfn "%d" i

looks great!

fizzbuzzPatternMatch

//ok
module fizzbuzzPatternMatch =
    let nums = [1..100]

    let fizzbuzz i = 
        match i with
        | i when i % 15 = 0 -> "fizzbuzz"
        | i when i % 3 = 0 -> "fizz"
        | i when i % 5 = 0 -> "buzz"
        | _ -> string i

    for i = 1 to 100 do
        fizzbuzz i |> printfn "%s"   

Great (u probably just forgot the list declaration on top). But out of curiosity, sometimes you will see a function keyword in code like this, it is just a syntax sugar for a function doing pattern matching on its parameter so:

let fizzbuzz i = 
    function
    | i when i % 15 = 0 -> "fizzbuzz"
    | i when i % 3 = 0 -> "fizz"
    | i when i % 5 = 0 -> "buzz"
    | i -> string i

is the same.

FizzbuzzRecursive

module FizzbuzzRecursive = 
    let nums = [1..100]

    let fizzbuzz i = 
        match i with
        | i when i % 15 = 0 -> "fizzbuzz"
        | i when i % 3 = 0 -> "fizz"
        | i when i % 5 = 0 -> "buzz"
        | _ -> string i
    
    let rec fizzbuzzRecursive (numList: int list) =
        if not numList.IsEmpty then
            printfn "%s" (fizzbuzz numList.Head)
            fizzbuzzRecursive numList.Tail

Good, but usually list manipulation is done using pattern matching:

let rec fizzbuzzRecursive (numList: int list) =
    match numList with
    | h::t -> printfn "%s" (fizzbuzz h)
              fizzbuzzRecursive t
    | [] -> ignore()

the :: is the cons operator that concatenates heads and tails. It is also usually a good practice to separate the side efects from the logic. (in large projects, this practice pushes dependencies to the edges of your program.):

let fizzBuzzRecursive = numList
    match numList with
    | h::t -> (fizzbuzz h)::(fizzBuzzRecursive t)
    | [] -> []

let printStringList strList  =
    for s in strList do printfn "%s"    

let program lst = fizzBuzzRecursive lst |> printStringList

or....

let rec fizzBuzzRecursive = function
    | h::t -> (fizzbuzz h)::(fizzBuzzRecursive t)
    | [] -> []

Succinct, but the above code is not tail-call optimized, we can go into that latter

FizzbuzzSeq

module FizzbuzzSeq = 
    let nums = Seq.init 100 id

    let fizzbuzz i = 
        match i with
        | i when i % 15 = 0 -> "fizzbuzz"
        | i when i % 3 = 0 -> "fizz"
        | i when i % 5 = 0 -> "buzz"
        | _ -> string i

    let fizzbuzzResult = fizzbuzz |> Seq.map <| nums

    Seq.iter (fun str -> printfn "%s" str) fizzbuzzResult 

It works, but usually we pass the function to Seq.map, so that it reads as Given this sequence, map its elements with this function

let fizzbuzzResult = nums |> Seq.map fizzbuzz 
                          |> Seq.iter (printfn "%s")

As a rule of thumb, try to avoid <| operator (at first)

FizzbuzzSumType

module FizzbuzzSumType = 
    type FizzBuzzAnswer = 
    | Fizz
    | Buzz
    | FizzBuzz

    type Answer = 
    | FBZ of FizzBuzzAnswer
    | Number of i: int

    let fizzbuzz i : Answer = 
        match i with
        | i when i % 15 = 0 -> FBZ(FizzBuzz)
        | i when i % 3 = 0 -> FBZ(Fizz)
        | i when i % 5 = 0 -> FBZ(Buzz)
        | _ -> Number(i)

    let toStr (x: Answer) : string =
        match x with
        | Number(i) -> string i
        | FBZ(FizzBuzz) -> "FizzBuzz"
        | FBZ(Fizz) -> "Fizz"
        | FBZ(Buzz) -> "Buzz"

    let printFizzbuzz (str: string) =
        printfn "%s" str

    let intToStr = fizzbuzz >> toStr

    // let result = Seq.map intToStr [1..100]
    Seq.iter (intToStr >> printFizzbuzz) [1..100]

I would personally use a single Sum type, to make it less noisy

type FizzBuzzAnswer = 
    | Fizz
    | Buzz
    | FizzBuzz
    | Number of i

And as before, I would try to push the "print" to the edge of the execution

[1..100] |> Seq.map (fizzbuzz >> toStr) |> Seq.iter (printfn "%s")

which also make the information flow more explicit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment