I’ve been looking for some little programs to work on in order to learn F#. Thankfully, I stumbled across Dustin Campbell’s blog, which led me to following site.
It’s really a lot of fun and a great way to learn F#. Dustin has been showing the solutions in F# and I’ve run across C# solutions, so I thought I’d compare how to do the problems in F# with how you would do them in Visual Basic.
Problem 1
Add all of the natural number below 1000 that are multiples of 3 or 5.
Problem 1 the F# way
I’m a newbie at F#, so I’ll admit to examining Dustin’s solution right off the bat. I take no credit for the following F# code. All I’ve done is update it for the CTP release.
let result =
seq {for n in 1 .. 999 do
if n % 3 = 0 or n % 5 = 0 then
yield n}
|> Seq.reduce (+)
printfn “%A” result
Let’s examine the parts real quick
· seq declares we will be using a sequence workflow.
· for n in 1 .. 999 do generates and iterates through number 1 to 999.
· if n % 3 = 0 or n % 5 = 0 then checks if n a multiple of 3 or 5
· yield n returns the result 1 number at a time
· |> Seq.reduce (+) sums up all the numbers in our generated sequence
And when we run our program, the number 233168 gets printed to the console.
Problem 1 the VB way
I was going to solve the problem in VB the standard brute force iteration way until I came across the following blog entry. Again, I take no credit for the following code. It has been scoffed from another source.
Dim result = Enumerable.Range(1, 999).Where(Function(n) n Mod 3 = 0 OrElse n Mod 5 = 0).Sum()
Let’s examine the parts real quick
· Enumerable.Range(1, 999) generates and iterates through number 1 to 999.
· Where(Function(n) n Mod 3 = 0 OrElse n Mod 5 = 0) checks if n a multiple of 3 or 5.
· We don’t need to yield the result one number at a time as the implementers of the Where method have already done if for us.
· Sum() sums up all the numbers in our generated sequence
Not too different from our F# solution. Linq monads are a form of what F# calls workflows. If we convert the Linq expression above to the more familiar syntax we get.
Dim result = (From n In Enumerable.Range(1, 999) _
Where (n Mod 3 = 0 OrElse n Mod 5 = 0) _
Select n).Sum()
I really can’t say this is any easier to read than the first example, but they both print 233168 to the console.
F# One Ups VB
So if VB can do what F# already does then why learn F#? Because we can do things like the following.
let result =
seq {for n in 1 .. 999 do
let (%%) n s = Seq.exists (fun x -> n % x = 0) s
if n %% [3;5] then
yield n}
|> Seq.reduce (+)
printfn “%A” result
We’ve defined a temporary function in the middle of our workflow that basically means “is a multiple of”. Now we just pass a list of numbers that we want to check n against. For instance,
if n %% [3;5;7;9] then
would mean, where n is a multiple of 3, 5, 7 or 9. VB has plans on adding multiline lambdas, but I haven’t heard of any support for defining and using those lambda’s later on in the workflow. We are allowed to bind functions to identifiers in VB. For instance,
let (%%) n s = Seq.exists (fun x -> n % x = 0) s
if n %% [3;5] then
can be translated into the following VB
Dim multiple_of = Function(n, s) s.Any(Function(x) n Mod x = 0)
Dim seq As New List(Of Integer)
seq.Add(3)
seq.Add(5)
Dim result = multiple_of(3, seq)
but we have no way of inserting this function identifier into our LINQ workflow. It would be nice to be able to do the following
Dim result = (From n In Enumerable.Range(1, 999) _
Dim multiple_of = Function(n, s) s.Any(Function(x) n Mod x = 0) _
Where (n multiple_of([3;5;7;9]) _
Select n).Sum()
Someday!
