Thursday, January 17, 2008

A few F# basics

I was driving to the Code Mash conference with a colleague last week and I started talking about F# and how I was really getting into it. He asked generally, "What's the main difference between F# and C#?". After drawing a complete blank and a long pause, I stammered out something like, there's really no one difference between the two languages, and began to ramble some of the differences I could recall. A few days later I went back and nosed through my copy of Robert Pickering's book; I refreshed what some of the main differences are. So I thought I'd jot some down. Disclaimer: I am just beginning to learn this language, everything here is my interpretation and I am sure there are more differences than the few I list. Identifiers and expressions - Identifier is the keyword to define a value. Expressions are any chunk of code that returns something.
let myname = "Nate"
In F#, as with other functional languages, all values are immutable. Once a value is assigned to an identifier the value never changes. Of course, like all languages, there are ways to let identifiers be mutable using the keyword mutable.

let mutable myName = "Nate"

myName <- "Etan"

Functions are identifiers- Functions in F# are first class entities and are treated just like identifiers.
let squares x = x * x
let cubes x = squares x * x
In this example, squares is the name of the function and x is the parameter. The function cubes takes it's parameter passes it to the square function. The result of the squares function gets included in the rest of the expression for cubes. Functions can also be curried. Currying is the process of passing a function with some arguments that returns you a function with a single argument. Consider the following snippet:
let p = 20
let add x y = x + y
let add13 = add 13
let answer = add13 p

answer = 33
Huh?? Let's take a walk through that. The add function has the signature of int -> int -> int, which reads; this function takes two ints and returns an int. The add13 function has the signature (int -> int) which reads; this function takes a function that returns an int and returns an int. The expression answer calls the add13 function, which calls the add function giving 1 parameter which gets assigned to x then p gets assigned to y on the add function. Type inference - F# is very strongly typed, but you don't have to explicitly declare the variable types. The F# compiler handles all that for you. Using FSI, you can see what the complier infers
> let s = "S"
val s : string
> let double = 2.3
val double : float
> let x = 0
val x : int
> let c = 'c'
val c : char
> let whatisthis q = q
val what : 'a -> 'a
The 'a means the complier could not infer what the type is so it uses a generic type. (Not to be confused with generics in C#.) Pattern matching and recursion - These two traits deserve their own respective posts. Pattern matching is conducive to if..elseif..else and switch statements in procedural languages and recursion means a function calls itself. Anonymous functions - anonymous functions, also called lambdas, that don't get an identifier. These functions are used as arguments to other functions. The keyword fun identifies these.
let divide q = (fun x y -> x / y) q 2
That's all for now, comments and feedback are welcome!

No comments: