localized/ja/11-Other/FSharpConsoleApplication/Fibonacci.fs (100 lines of code) (raw):

module MyFibonnaci // 1. shamelessly imperative version let fib1 n = // function syntax. n and return are deduced if n < 1 then failwith "n must be at least 1" // throws System.Exception else if n = 1 then // = means comparison 0 // no statements, only expressions else // if, else if, else is very rare... let mutable x = 0 // vars not mutable by default let mutable y = 1 for i in [3..n] do // must iterate something - here a (generated) list let x' = y // can use ' in var names let y' = x+y x <- x' // <- means assigment (to mutable) y <- y' y fib1 14 // test // 1.1 Refactor to use simple pattern matching let fib1_1 n = match n with | _ when n < 1 -> failwith "n must be at least 1" | 1 -> 0 | _ -> // don't need matched value here (already have it) let mutable x, y = 0, 1 // multi value assignment (actually a pattern match on a tuple) for i in [3..n] do let x', y' = y, x+y x <- x' y <- y' y fib1_1 14 // test // 2. Recursive version // gets rid of the mutability *and* the imperative loop // - much more functional already let rec fib2 n = // need 'rec' keyword match n with | _ when n < 1 -> failwith "n must be at least 1" | 1 -> 0 | 2 -> 1 | _ -> fib2(n-1) + fib2 (n-2) fib2 14 // test List.map fib2 [1..14] // We can get all of the first 10 fibonacci numbers like this [1..14] |> List.map fib2 // but more idiomatic like this // 3. Since we're calculating all values to nth as we go // we may as well return them as a list let rec fib3 n = match n with | _ when n < 1 -> failwith "n must be at least 1" | 1 -> [0] // syntax for list of 1 element | 2 -> [0;1] // syntax for list of 2 elements | _ -> let a = fib3 (n-1) a @ [a.[n-2]+a.[n-3]] // Use @ to concat two lists. Use .[x] to index list // Functional lists are singly linked. In this case we always want the values at the other end // so getting them is a bit awkward (cleaner way shortly...) fib3 14 // test // 4. If we're ok for the list to be backwards we can // get to the previous values more cleanly let rec fib4 n = match n with | _ when n < 1 -> failwith "n must be at least 1" | 1 -> [0] | 2 -> [1;0] | _ -> let a = fib4 (n-1) a.Head + a.Tail.Head :: a fib4 14 // test fib4 14 |> List.rev // We can reverse the list like this // 4.1 We can wrap that up in a function let fib4_1 n = fib4 n |> List.rev fib4_1 14 // test // 4.2 Or keep the reversed list generator encapsulated let fib4_2 n = let rec rfib n = match n with | _ when n < 1 -> failwith "n must be at least 1" | 1 -> [0] | 2 -> [1;0] | _ -> let a = rfib (n-1) a.Head + a.Tail.Head :: a rfib n |> List.rev fib4_2 14 // test // 5. We can avoid the recursion by using higher level functions let fib5 n = {3..n} // generate a range to operate on |> Seq.fold( fun f _ -> (f.Head + f.Tail.Head) :: f ) [1;0] |> List.rev fib5 14 // test // 6. We can also generate a sequence lazily let fib6 () = let rec fib i j = // Helper function which operators on last two values seq { // Sequence expression yield j // Yield a single value yield! fib j (i+j) // Yield! to yield a sequence } seq { yield 0 yield! fib 0 1 } fib6() |> Seq.take 14 |> Seq.toList // test