Professional Documents
Culture Documents
F# is valuable to programmers at any skill level; it combines best features of functional and object
oriented programming styles into a uniquely productive language.
Programming languages are becoming more functional every year. For example, features such
as generic programming, type inference, list comprehensions, functions as values, and
anonymous types have traditionally existed as staples of functional programming, have quickly
become mainstream features of Java, C#, Delphi and even Fortran. In the future, next generation
programming languages will continue to evolve as hybrid functional / imperative programming
languages.
Unlike many other strongly typed languages, F# often does not require programmers to use type
annotations when declaring functions and variables. Instead, F# attempts to work out the types
for you, based on the way that variables are used on code.
(* This is a
multi-line comment *)
#light
open System
let rec fib n =
if n < 2 then 1 else fib (n-2) + fib(n-1)
let _ = Console.ReadKey()
Most F# code files contain the #light directive at the top. This keyword makes
whitespace significant and allows programmers to omit certain redundant tokens such
as in, ;, begin, and end.
The body of the F# file usually contains functions to implement the business logic in an
application.
main()
(*
This is a top-level statement because it's
not nested in any other functions. This calls
into the main method to run the main loop.
*)
In the real world, an object is a "real" thing. A cat, person, computer, and a roll of duct tape are
all "real" things in the tangible sense. When we think about these things, we can broadly describe
them in terms of a number of attributes:
Properties: a person has a name, a cat has four legs, computers have a pricetag, duct
tape is sticky.
Behaviors: a person reads the newspaper, cats sleep all day, computers crunch
numbers, duct tape attaches things to other things.
Types/group membership: an employee is a type of person, a cat is a pet, a Dell and Mac
are types are computers, duct tape is part of the broader family of adhesives.
Before you create an object, you have to identify the properties of your object and
describe what it does. You define properties and methods of an object in a class. There
are actually two different syntaxes for defining a class: an implicit syntax and an
explicit syntax.
This syntax above is not as daunting as it looks. Here's a simple class written in implicit
style:
type Account(number : int, holder : string) = class
let mutable amount = 0m
member x.Number = number
member x.Holder = holder
member x.Amount = amount
ou create an instance of Account by using the new keyword and passing the appropriate
parameters into the constructor as follows:
let bob = new Account(123456, "Bob's Saving")
After we can create an instance of our Account, we can access its properties
Instance members, which can only be called from an object instance created using
the new keyword.
Static members, which are not associated with any object instance.
member x.Num
with get() = num
and set(value) =
if value > 10 || value < 0 then
raise (new Exception("Values must be between 0 and 10"))
else
num <- value
end
Comments
Types
On those occasions where F# cannot work out the types correctly, the programmer can provide
explicit annotations to guide F# in the right direction. For example, as mentioned above, math
operators default to operations on integers
> let add (x : float) (y : float) = x + y;;
val add : float -> float -> float
Primitive types
nit , bool , char , int and float , as well as several compound types such
as string > ();;
val it : unit = ()
> true;;
val it : bool = true
> 'a';;
val it : char = 'a'
> 3;;
val it : int = 3
> 2.4;;
val it : float = 2.4
> "foobar";;
val it : string = "foobar"
Arithmetic
The numeric types, such as int and float , provide various arithmetic operations:
> 1 + 2 * 3;;
val it : int = 7
> 3.4 + 2.3 * 7.7;;
val it : float = 21.11
Variants
> type expr =
| Int of int
| Var of string
| Plus of expr * expr
| Times of expr * expr;;
type expr =
| Int of int
| Var of string
| Plus of expr * expr
| Times of expr * expr;;
The match ... with construct evaluates the given expression and then
compares the result with a sequence of pattern matches:
prints out
1
2
1
Once symbols are bound to values, they cannot be assigned a new value
Immutability allows programmers to pass values to functions without worrying that the
function will change the value's state in unpredictable ways. Additionally, since value can't
be mutated, programmers can process data shared across many threads without fear that
the data will be mutated by another process; as a result, programmers can write
multithreaded code without locks, and a whole class of errors related to race conditions and
dead locking can be eliminated.
Functional programmers generally simulate state by passing extra parameters to functions;
objects are "mutated" by creating an entirely new instance of an object with the desired
changes and letting the garbage collector throw away the old instances if they are not
needed.
Example
> let rec pow n x =
match n with
| 0 -> 1.
| n -> x * pow (n - 1) x;;
val pow : int -> float -> float
open System
let main() =
let printAccounts() =
[homer; marge] |> Seq.iter printAccount
printfn "\nInializing account"
homer.Deposit 50M
marge.Deposit 100M
printAccounts()
main()
type Account =
class
new : number:int * holder:string -> Account
member Deposit : value:decimal -> unit
member Withdraw : value:decimal -> unit
member Amount : decimal
member Holder : string
member Number : int
end
val homer : Account
val marge : Account
val transfer : decimal -> Account -> Account -> unit
val printAccount : Account -> unit
Car
open System
open System.Net
(* first constructor *)
new (owner) =
{ used = false;
owner = owner;
mileage = 0 }
(* another constructor *)
new (owner, mileage) =
{ used = true;
owner = owner;
mileage = mileage }
end
let main() =
let printCar (c : Car) =
printfn "c.used: %b, c.owner: %s, c.mileage: %i" c.used c.owner
c.mileage
main()
F# Represe
.NET Type Size Range Example
Type nts
Integral Types
8-bit
1 42y
sbyte System.SByte -128 to 127 signed
byte -11y
integer
42uy 8-bit
byte System.Byte 1
0 to 255 200uy unsigned
byte
integer
16-bit
2 42s
int16 System.Int16 -32768 to 32767 signed
bytes -11s
integer
32-bit
int/in 4 -2,147,483,648 to 42
System.Int32 signed
t32 bytes 2,147,483,647 -11
integer
-
9,223,372,036,854, 42L 64-bit
int64 System.Int64 8
775,808 to -11L signed
bytes
9,223,372,036,854, integer
775,807
42I arbitrary
bigin System.Numerics.Bi ??
any integer 14999999999999999999999 precisio
t gInteger bytes 999999999I n integer
Floating Point Types
32-bit
signed
floating
float 4 42.0F point
System.Single ±1.5e-45 to ±3.4e38 -11.0F
32 bytes number
(7
significa
nt digits)
64-bit
signed
floating
8 ±5.0e-324 to 42.0 point
float System.Double
bytes ±1.7e308 -11.0 number
(15-16
significa
nt digits)
128-bit
signed
floating
decim 16 ±1.0e−28 to 42.0M point
System.Decimal
al bytes ±7.9e28 -11.0M number
(28-29
significa
nt digits)
Text Types
Single
2 'x' unicode
char System.Char U+0000 to U+ffff
bytes '\t' characte
rs
20 +
(2 *
strin string
System.String 0 to about 2 billion "Hello" Unicode
g 's "World"
characters text
lengt
h)
bytes
Other Types
Unit, the datatype with only one value, equivalent to void in C-style languages.
Tuple types, which are ad hoc data structures that programmers can use to group related
values into a single object.
Record types, which are similar to tuples, but provide named fields to access data held
by the record object.
Discriminated unions, which are used to create very well-defined type hierarchies and
hierarchical data structures.
Lists, Maps, and Sets, which represent immutable versions of a stack, hashtable, and set
data structures, respectively.
Sequences, which represent a lazy list of items computed on-demand.
Computation expressions, which serve the same purpose as monads in Haskell, allowing
programmers to write continuation-style code in an imperative style.
F# is a statically typed language, meaning that compiler knows the datatype of variables and
functions at compile time. F# is also strongly typed, meaning that a variable bound to ints
cannot be rebound to strings at some later point; an int variable is forever tied to int data.
and environment =
Map.ofList [
"*", Function(Multiply)
"-", Function(Subtract)
"if", Special(If)]
#light
2:
3: let ToAddress = "MyToAddress@domain.com"
4: let FromAddress = "MyFromAddress@domain.com"
5: let Subject = "F# Email Example"
6: let SMTPServer = "127.0.0.1"
7:
8: open System.Net.Mail
9:
10: let mm = new MailMessage()
11: mm.To.Add(ToAddress)
12: mm.From <- new MailAddress(FromAddress)
13: mm.Subject <- Subject
14: mm.Body <- "Hello, F# Email"
15:
16: let filePath = @".\CommaDelimitedFile.txt"
17: let att = new Attachment(filePath)
18: mm.Attachments.Add(att)
19:
20: let client = new SmtpClient()
21: client.Host <- SMTPServer
22: client.Send(mm)