FSharp - gregorymorrison/euler1 GitHub Wiki

F#, introduced in 2005, is Microsoft's version of OCaml for .NET. Which means that it's a functional language that supports OOP and the .NET framework, among other things. So, without learning anything about F#, let's see how compatible F# is with OCaml. Let's see if it can execute this OCaml version of Euler1 a commenter sent me:

(* Euler1 in F# *)

let euler x =
    let rec f i n =
        match i with
            | 0 -> n
            | i when i % 3 = 0 || i % 5 = 0 -> f (i-1) (n+1)
            | _ -> f (i-1) n
    in f x 0

printfn "%i" (euler 999)

Well, the F# team has a handy-dandy web client that will let you try F# without installing anything - let's try that. Crossing my fingers, I pasted my code into the window and clicked Run. Wouldn't you know it - it worked! I got the following output:

233168
val euler : int -> int

That was too easy! Let's try my other OCaml example:

(* Euler1 in F# *)

let rec range i j = i :: if i=j then [] else (range (i+1) j);;

let myTest = fun x -> x % 3 = 0 || x % 5 = 0;;

let sum = List.fold (+) 0;;

let euler n = range 0 n |> List.filter myTest |> sum;;

[<EntryPoint>]
let main argv =
    printfn "Euler1 = %d" (euler 999)
    0

Well, at first it threw errors, but after changing the names of the fold and mod functions, it worked! It produces a lot of gibberish along with the solution:

val range : int -> int -> int list
>
val sum : int list -> int
>
val myTest : int -> bool
>
val euler : int -> int
> 233168
val it : unit = ()
> >

Here is an example that uses the canonical map, filter, and fold. Notice here that we actually don't need the map function, so it just returns what was passed into it; it is here only for illustration:

(* Euler1 in F# *)

let rec range i j = i :: if i=j then [] else (range (i+1) j);;

let myMap = List.map (fun x -> x);;

let myFilter = List.filter (fun x -> x % 3 = 0 || x % 5 = 0);;

let myFold = List.fold (+) 0;;

let euler n = range 0 n |> myMap |> myFilter |> myFold;;

Printf.printf "Euler1 = %d\n" (euler 999);;

Here is an example that uses the built-in sequence library functions. We simply generate three arrays of ints up to 999 - one step 3, one step 5, and one step 15. The step-15 ints are subtracted from the other sequences because they're going to be the duplicate values found in the sequences of 3 and 5:

(* Euler1 in F# *)

let euler n = Seq.sum(seq{0..3..n}) + Seq.sum(seq{0..5..n}) - Seq.sum(seq{0..15..n})

Printf.printf "Euler1 = %d\n" (euler 999);;

Here is another version of the above, using a slightly different algorithm. Here we generate three arrays of ints - one step 3, one step 15 starting at 5, and one step 15 starting at 10. This covers all the ints divisible by 3 or 5 with no overlaps, and we simply sum them all up. Cool!

(* Euler1 in F# *)

let euler n = Seq.sum(seq{0..3..n}) + Seq.sum(seq{5..20..n}) + Seq.sum(seq{10..25..n})

Printf.printf "Euler1 = %d\n" (euler 999);;

So it appears that F# really is OCaml on .NET.

To set up a compiler, I tried these instructions. I tried installing .NET Core on Ubuntu, but got dependency errors. I then tried installing Mono, and although it took a few minutes, it worked fine. To run your code:

$ fsharpc euler1.fs -o euler1
Microsoft (R) F# Compiler version 10.2.3 for F# 4.5
Copyright (c) Microsoft Corporation. All Rights Reserved.
$ mono euler1
Euler1 = 233168
$

Pro tip: to only have to type the file name once, enter the whole thing in one line using xargs like so:

$ echo "euler1" | xargs -I {} sh -c 'fsharpc $1.fs -o $1 && mono $1' sh {}
Microsoft (R) F# Compiler version 10.2.3 for F# 4.5
Copyright (c) Microsoft Corporation. All Rights Reserved.
Euler1 = 233168
$
⚠️ **GitHub.com Fallback** ⚠️