Adventures in F# - F# 101 Part 4

Time for another adventure in F#, covering the 101 level basics of the language and why I love it as much as I do.  This time we're going to cover some topics such as custom operators, lists and so on. 

As I want to stress in every installment of this series, the importance of functional programming and its influence on the .NET framework.  Don Syme, the creator of F# was instrumental in bringing generics into the .NET framework.  With such things as lambdas, object initializers, collection initializers, implicit initialization partially came from ideas from functional programming and F#. 

Where We Are

Before we begin today, let's catch up to where we are today:
Drink up the goodness and let's continue.  Today, I'd like to cover the following topics:
  • A Brief History of F#
  • Operators
  • Lists
The list may seem small, but there is a lot to learn with all of this.  But before we get technical again, let's step back and get a brief lesson of how F# came to be.

A Little History Lesson

As you may know, functional programming itself is one of the older programming paradigms that dates back to the 1950s.  In fact, as with most things, it can be traced back to Lisp in the late 1950s.  Like I've said before, most good things in programming nowadays can trace their history to Lisp, or Smalltalk

Anyhow, back in 2002, Don Syme and a team at Microsoft Research wanted an Metalanguage (ML) approach to language design on the .NET platform.  While this project was going on, Don was also working on implementing generics in the .NET platform as well.  These two projects worked there way into becoming F# which made its first appearance in 2005.

As you may note from looking at the F# libraries such as FSharp.Compatibility.dll and the namespace Microsoft.FSharp.Compatibility.OCaml, it shares a common base with Objective Caml (OCaml).  OCaml itself, another language in the ML family and been around since 1996.  It also borrowed for Haskell as well in regards to sequences and workflows.  But, in the end, as you may know, F# splits from those languages quite a bit because it allows for imperative and object oriented programming.  That's the really interesting piece of this puzzle is to be able to interoperate with other .NET languages as if they were first class citizens.

One thing that I found particularly interesting about F# is that it is very portable, unlike other .NET languages.  What I mean by that is that they provide you with the source so that you could use this with Mono, Shared Source CLI or any other ECMA 335 implementation.  I've been able to fire up a Linux box with Mono and sure enough it compiles and runs without fail.  Now onto the technical details...

Operators

Operators are an interesting and compelling feature in F#.  Most modern languages support this feature except for say Java to overload operators.  I think it's a compelling feature in the way of dealing with DSLs and such.  But anyways, F# supports two types of operators, the prefix and infix types.  The prefix operator type is an operator that takes one operand.  In order to be prefix, it means that it precedes its operand such as (-x).  The infix operator type takes two or more arguments.  An example of this kind of operator is (x + y).

There are many operators in the F# libraries quite frankly and I'll list just a few of them:

Arithmetic Operators
Operator Meaning
+ Unchecked addition
- Unchecked subtraction
* Unchecked multiplication
/ Division
% Modulus
- Unary Negation

Bitwise Operators
Operator Meaning
&&& Bitwise and
||| Bitwise or
^^^ Bitwise Exclusive Or
~~~ Bitwise Negation
<<< Left shift
>>> Right shift

Assignment and Others
Operator Meaning
<- Property Assignment
-> Lambda Operator
:: List  Concatenation (cons)
|> Forward Operator
[[ ] Index Operator
:? Pattern Match .NET Type

And many many more.  It's a massive array of built-in operators...

Back to the subject at hand.  As in C# and other .NET languages, the operators are overloaded.  But unlike C# for example, both operands for the operator must be of the same type.  But unlike C#, F# will allow you to not only define, but redefine operators as well.  Below I'll show an example of using the common concat operator with strings and then redefine the division operator to do something really stupid and do multiplication instead.  Aren't I crafty?

#light

 

let fooBar = "Foo" + "Bar"

print_string fooBar

 

let (/) a b = a * b

printfn "%i" (4 / 2)


So, as you can see it's rather powerful what we can do with existing operators.  But, with F#, we can also define our own operators we wish to use.  In fact we can use any of the below as our new operator.

! $ % & * / + - . < = > ? @ ^ | ~ as well as a :

As I did above, it should be no different for us to create our new operator.  Let's walk through a simple operator that does raise to the power of two of the first operand and add the second.

#light

 

let ( *:/ ) a b = (a * a) + b

printfn "%i" (45 *:/ 42)


If you're curious like me what that actually looks like, let's look through .NET Reflector and see what it creates for us.  I'll just copy and paste the results here:

public static int op_MultiplyColonDivide(int a, int b)

{

    return ((a * a) + b);

}


But we can also define operators for our custom types as well.  Let's go ahead and define a simple type called Point and then define the addition and subtraction operators.  This syntax should look rather familiar and to me, it looks a little Ruby-esque. 

#light

 

type Point(dx:float, dy:float) =

  member x.DX = dx

  member x.DY = dy

 

  static member (+) (p1:Point, p2:Point) =

    Point(p1.DX + p2.DX, p1.DY + p2.DY)

 

  static member (-)(p1:Point, p2:Point) =

    Point(p1.DX - p2.DX, p1.DY - p2.DY)

 

  override x.ToString() =

    sprintf "DX=%f, DY=%f" x.DX x.DY

 

let p1 = new Point(5.0, 6.0)

let p2 = new Point(7.0, 8.0)

let p3 = p2 - p1

let p4 = p2 + p1

 

printfn "p3 = %s" (p3.ToString())

printfn "p4 = %s" (p4.ToString())


Lists

Lists are one of the most fundamental pieces that is built right into the F# language itself.  The language itself around the use of lists is a bit verbose, but I'll cover the basics through the use of code.  Lists in F# are immutable, meaning that once they are created, they cannot be altered.  Think of them like a .NET System.Array in a way, but a little bit more powerful.  Do not get them confused though with F# Arrays which are entirely different and will be talked about later.  Let's show the basics here below about lists:

#light

 

let empty = [] (* Empty List *)

let oneItemInList = 1 :: [] (* One Item *)

let twoItemsInList = 1 :: 2 :: [] (* Two Items *)

List.iter(fun x -> printfn "%i" x) twoItemsInList (* Iterate Over List *)

 

let threeItems = [1 ; 2 ; 3] (* Shorthand notation *)

let listOfList = [[1 ; 2 ; 3]; [4 ; 5; 6]; [7 ; 8 ; 9]]

List.iter(fun x -> print_any x) listOfList (* Iterate over list of list *)


As you can see from the example above there are a couple ways of declaring lists, including the verbose way which includes the empty list, or the classic style of putting inside of square brackets.  What's more interesting is to have lists of lists as well.

Another interesting aspect of F# lists is List Comprehensions.  Using this syntax, we can specify ranges to use in our lists.  If you specify a double period (..) in your list, it fills in the rest of the values.  I have three samples below which includes 0 to 100, lower-case a to z and upper-case A to Z.

You can also specify steps in the numbers as well which is much like a for loop with a step in there.  Note that characters do not support the stepping capability.  To use the stepping capability, the format is (lower bound, step value, upper bound).  Below I have a sample which pulls all even numbers from 100 to 0 and stepping -2 each time.

For loops can also be used in which you can transform each item along the way.  To use this one, use this for keyword and the lower end to upper end and then the lambda to modify the value.  Below I have an example where I double each number from 1 to 20.

Another example of a for loop is to create a loop in which you specify a when guard.  You can then only print out values that match your criteria.  The example I have below is to print all odd numbers using the formula when x % 2 <> 0.

#light

 

let zeroToOneHundred = [0 .. 100] (* 0 to 100 *)

let lowerCaseAToZ = ['a' .. 'z'] (* Lower-case a-z *)

let upperCaseAToZ = ['A' .. 'Z'] (* Upper-case a-z *)

let evensFromOneHundred = [100 .. -2 .. 0] (* 100 to 0 skipping every 2 *)

let doubledValues =

  { for x in 1 .. 20 -> x + x } (* Double each value from 1 to 20 *)

 

let odds n =

  { for x in 1 .. n when x % 2 <> 0 -> x } (* Print all odd numbers *)

print_any (odds 20)


And I've only just begun to touch the basics of lists.  Dustin Campell also covered lists recently on his Why I Love F# Series.

Conclusion

We still have plenty to go before I'd say we were done with a 101 level exercise with F#.  We still have yet to cover pattern matching, lazy evaluation, exception management and even using F# with imperative and object oriented code.  So, subscribe and stick around.  Until next time...

kick it on DotNetKicks.com

11 Comments

Comments have been disabled for this content.