<Query Kind="FSharpProgram" />

let fact n:int = 
    let mutable m = n
    let mutable f = 1
    while (m >= 1) do 
        f <- f * m
        m <- m - 1
    f
printfn "Imperative: %A" (fact 5)

// ---

let rec fact' n = 
    if n <= 0 then 1 
    else (fact' (n-1)) * n
printfn "Recursive: %A" (fact' 5)

// ---

let fact'' n = 
    let rec fact_tailrec n acc =
        if (n <= 0) then acc
        else fact_tailrec (n-1) (n*acc)
    fact_tailrec n 1
printfn "Tail Recursive: %A" (fact'' 5)

// ---

let hylofact n = 
    seq {1 .. max 1 n}
    |> Seq.reduce (*) 
printfn "Hylomorphic: %A" (hylofact 5)

// ---

let anafact' = fun n -> seq {1 .. max 1 n}
let catafact' = Seq.reduce<int> (*)
let hylofact' = anafact' >> catafact'

printfn "anafact': %A" (anafact' 5)
printfn "hylofact': %A" (hylofact' 5)

// ---

let anafact'' n = 
    Seq.unfold (
        fun k -> 
            if k <= 0 then None 
            else Some (k, k-1))
        n

let catafact'' (s:seq<int>) = Seq.fold (*) 1 s

let hylofact'' = anafact'' >> catafact''

printfn "anafact'': %A" (anafact'' 5)
printfn "hylofact'': %A" (hylofact'' 5)

// ---