Blue Theme Orange Theme Green Theme Red Theme
 
MindFusion's Components
Home | Forums | Videos | Photos | Downloads | Blogs | Interviews | Jobs | Beginners | Training
 | Consulting  
Submit an Article Submit a Blog 
 Login Close
User Id:
Password:
 
Forgot Password
Forgot Username
Why Register
 Jump to
Skip Navigation Links
TechnologyExpand Technology
WebsiteExpand Website
 Resources  
Close
 Our Network  
Close
Search :       Advanced Search »
Home » F# » F# Tuples and Binding (and more Binding)

F# Tuples and Binding (and more Binding)

Binding in F# is similar to using variables in C# but there are some big differences. This article discusses one of the most used keywords in F# for binding ("let") and how it is different than setting a C# variable. I also cover the tuple F# data structure.

Author Rank:
Total page views :  6098
Total downloads : 
   Print Read/Post comments Post a comment  Similar Articles  
   Email to a friend  Bookmark  Author's other articles  
 
Become a Sponsor


What's A Tuple?

First we have to look at a core data type in F# called a tuple.  Tuples are a way of grouping other data types.  Tuples are immutable data structures that can have any number of items.  (By immutable, I mean that it can't be "mutated" or that there are no property setters, only property getters, like a C# String object.)

The number of items we declare in a tuple probably should be kept to a manageable number (more than seven items starts to get really confusing, at least for my human brain, and I would probably consider a different data structure if I needed more than 7 or so type "slots").

Tuples are declared by surrounding a comma separated list of values in parenthesis.  The data type that results are the types separated by the ‘*' character.  Here is a tuple of an int and a string:

> (4, "Hello World");;
val it : int * string = (4, "Hello World")

If we look at it from a C# perspective this is the type of structure we have with a two-member tuple:

public class Tuple<T, U>
{
    public Tuple(T pValue1, U pValue2)
    {
        m_value1 = pValue1;
        m_value2 = pValue2;
    }

    private T m_value1;
    private U m_value2;

    public T Value1
    {
        get { return m_value1; }
    }

    public U Value2
    {
        get { return m_value2; }
    }
}

And we would declare an instance in C# (.NET 3.5) as follows:

Tuple<Int32, String> value =
    new Tuple<int, string>(
        4,
        "Hello World");

Of course we could have a structure with many more items

> (4, '4', "4", (fun x->x+4), 4.0, (fun x->x+ 4.0));;
val it : int * char * string * (int -> int) * float * (float -> float)
= (4, '4', "4", <fun:it@5>, 4.0, <fun:it@5_1>)

Which would be a pretty messy generic data type in C#:

public class Tuple<T, U, V, W, X, Y>
{
    public Tuple(T pValue1, U pValue2, V pValue3, W pValue4, X pValue5, Y pValue6)
    {
        m_value1 = pValue1;
        m_value2 = pValue2;
        m_value3 = pValue3;
        m_value4 = pValue4;
        m_value5 = pValue5;
        m_value6 = pValue6;
    }

    private T m_value1;
    private U m_value2;
    private V m_value3;
    private W m_value4;
    private X m_value5;
    private Y m_value6;

    public T Value1
    {
        get { return m_value1; }
    }

    public U Value2
    {
        get { return m_value2; }
    }

    public V Value3
    {
        get { return m_value3; }
    }

    public W Value4
    {
        get { return m_value4; }
    }

    public X Value5
    {
        get { return m_value5; }
    }

    public Y Value6
    {
        get { return m_value6; }
    }
}

And the declaration alone would be almost unmanagable in C#:

Tuple<Int32, Char, String, Func<Int32, Int32>, Double, Func<Double, Double>> value2 =
    new Tuple<int, char, string, Func<int, int>, double, Func<double, double>>(
        4,
        '4',
        "4",
        x => x + 4,
        4.0,
        x => x + 4.0);

One of the really nice things about F# is how concise the code is because everything is generic by default and we only declare the type if we want to (which we'll get to in a bit).

Binding Part 1.

In F# we can assign a value to a placeholder through binding.  The syntax for binding is first using the "let" keyword, followed by the placeholder name followed by an equal sign and then the value.

Here we are binding the value 4 to the placeholder x.  Notice the response telling us that the type of x is an integer.

> let x = 4;;
val x : int

This will look very familiar to C# programmers. (Note: If we use the F# interactive window, the placeholders will last until we close our Studio process or type "#quit" to reset our F# interactive session)

Now, wherever we want to use the integer "4", we can substitute our placeholder "x" as in the following example:

> x + 1;;
val it : int = 5

We can also bind to functions as in the following example:

> let f = (fun x -> x + 1);;
val f : int -> int

> f;;
val it : (int -> int) = <fun:clo@0>

> f x;;
val it : int = 5

Binding Part II.

Ok, now is where we depart from what we know in C# and can see why we don't consider F# binding the equivalent of assigning a variable some value in C#.

Remember tuples?  Well, we can bind to multiple placeholders using a tuple as follows:

> let (m,n) = (4, "Hello World");;
val m : int
val n : string

Notice that the placeholders "m" and "n" did not have to be declared before our functions but we have bound the value "4" to our placeholder "m" and the value "Hello World" to our placeholder "n" anyways.

> m;;
val it : int = 4

> n;;
val it : string = "Hello World"

Because functions are first class citizens of F#, we also have a more concise way to bind to F# function placeholders.  This is how we can declare a function with one input parameter "x"

> f x = x + 1;;

val it : bool = true

Notice how the type is inferred for us and we don't have to explicitly declare it as we would have had to do in  C#:

> f;;

val it : (int -> int) = <fun:clo@0_1>

In an earlier article I mentioned that sometimes we have to help F# figure out the type.  Let's say we wanted to build a function that added something to the end of a string:

> f x = x + " World";;

  f x = x + " World";;
  ----------^^^^^^^^^
stdin(25,10): error: FS0001: This expression has type
      string
but is here used with type
      int
stopped due to error

Right now I can already hear you thinking "Dude! I meant for you to use a string…"

Here, we get an error because the F# compiler sees a type conflict between our operation ‘+' which is an "int -> int" and the string " World".  Remember the syntax we saw earlier when we saw the type of the placeholder?

> let x = 4;;

val x : int

We can use the same syntax to constrain our type so our new string appending function will work by placing a colon after our input parameter followed by the type we want:

> let f x:string = x + " World";;

val f : string -> string

And now we can happily continue on our way with our new append function working as expected:

> f "Hello";;

val it : string = "Hello World"

We can also either pass tuples to functions as well as using a list of parameters.  For example, we can declare a function with two inputs as follows:

> let f (x:string) y = x + " " + y;;

val f : string -> string -> string

Notice how if we give the compiler a little bit of a hint with "x", it can figure out what type "y" is supposed to be.

And we can call our function as follows:

> f "Hello" "World";;

val it : string = "Hello World"

Similarly, we can pass a tuple as input to a function:

let f ((x:string), y) = x + " " + y;;

val f : string * string -> string

Notice how our function type is now "string * string -> string" which has a tuple ("string * string") instead of our previous "string -> string -> string" signature.  The function with a tupled argument ("string * string -> string") would be considered a function in non-curried form, while the function with no tuples ("string -> string -> string") would be considered to be curried.  In a future article I'll discuss how to move back and forth between the curried and non-curried formats and the reasons and drawbacks for doing this.

This should give you a bit of an idea of how F# binding is a bit different from C# variable assignments.

We can get values out of a tuple by defining a simple function:

> let first (x,y) = x;;

val first : 'a * 'b -> 'a

Our function type ('a * 'b -> 'a) says that if we have a tuple with something of type a in the first slot and something of type b in the second slot, we'll get something of type a as an output.

> first ("Hello", "World");;

val it : string = "Hello"

And you can see it works as expected.

Binding Part III

We can also have nested "let"s, but first let's turn on the light syntax option by typing "#light;;" in F# Interactive.  This will allow us to use an even more concise syntax where whitespace matters and makes for easier readin' code.

> #light;;

Here's another feature of the "let" binding keyword. We can "nest" lets to build more complex functions as in the following example.

>
let f x:int =
  let square m = m * m
  x |> square |> square;;

val f : int -> int

> f 2;;

val it : int = 16

(If the forward pipe operator "|>" is throwing you for a loop, check out my earlier article on the operator.)

Let's walk through what we have. 

We have obviously built a function that takes and int and returns an int (we know that from the signature displayed which is "int -> int").  This function has an internal function we bound to "square" that multiplies and integer with itself.  Notice how the compiler figures out the type of "square" from our single constraint on "x".

let f x:float =
  let square m = m *
  x |> square |> square;;

As an aside.. . we could have done the same thing and constrained the type to float and the compiler figures out what we mean:

>
let f x:float =
  let square m = m * m
  x |> square |> square;;

val f : float -> float

But I digress.

Our inner function is scoped to the outer.  Meaning that all the inner "lets" are only available to the outer "let", so "square" will not be defined outside the context of our function "f" and can't bee seen by F# interactive:

> square;;
  square;;
  ^^^^^^^
stdin(67,0): error: FS0039: The value or constructor 'square' is not defined.
stopped due to error

The last line of our function defines the output where we specify to take the input value "x" and push the result through our "square" function and take the result of that and push it through our "square" function again:

let f x:float =
  let square m = m * m
  x |> square |> square;;

And, as always, we terminate our instructions with the double semi-colon:

let f x:float =
  let square m = m * m
  x |> square |> square;;

If we look at a similar function in C# it would look like this:

public Int32 f(Int32 x)
{
    Func<Int32, Int32> square = m => m * m;
    return square(square(x));
}

If you are having problems with the lambda syntax, check out my earlier article on anonymous delegates and lambda syntax in C#.  This is a good illustration of how C# is becoming more "functional" and (to me) another good reason to wrap my mind around F# in order to take full advantage of all the opportunities available with the new C# functional language features.

We can have nested lets that go as many levels deep as we want.  If you want do drive yourself a little crazier, here's a little F# puzzle… see if you can figure out what this function will do:

let f x:int =
  let g y =
    let h z = z * z
    (h y) * (h y)
  g x;;

I'll leave this up to you (if you are really curious maybe it will get you to download F# and give it a shot).  After you figure it out, you'll see how flexible and expressive F# is which give us as developers many ways to solve problems (some more convoluted than others).

That's about it for this F# binding and tuple tour, I hope you enjoyed it.  I'll be back soon to look at more F# language features.

Until next time,
Happy coding


Login to add your contents and source code to this article
 About the author
 
Matthew Cochran
Looking for C# Consulting?
C# Consulting is founded in 2002 by the founders of C# Corner. Unlike a traditional consulting company, our consultants are well-known experts in .NET and many of them are MVPs, authors, and trainers. We specialize in Microsoft .NET development and utilize Agile Development and Extreme Programming practices to provide fast pace quick turnaround results. Our software development model is a mix of Agile Development, traditional SDLC, and Waterfall models.
Click here to learn more about C# Consulting.
 
Introducing MaxV - one click. infinite control. Hyper-V Hosting from MaximumASP.
Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon. Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees. As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
Dynamic PDF
ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications.
Go.NET
Build custom interactive diagrams, network, workflow editors, flowcharts, or software design tools. Includes many predefined kinds of nodes, links, and basic shapes. Supports layers, scrolling, zooming, selection, drag-and-drop, clipboard, in-place editing, tooltips, grids, printing, overview window, palette. 100% implemented in C# as a managed .NET Control. Document/View/Tool architecture with many properties&events. Optional automatic layout.
Dundas Software
Dundas Chart for .NET is the most advanced .NET charting package available today.  With an extremely complete feature set, elegant architecture and easy implementation, Dundas Chart can quickly add advanced Charting functionality to enhance and transform ASP.NET and Windows Forms applications.  Whether you are implementing charting into internal projects, or building applications for clients, Dundas Chart offers advanced technology and advanced results to get the most out of data.
Clickatell's SMS Gateway
Clickatell's Developer Solutions allow you to SMS enable any website or application via a range of API's. Learn More about our API connections.
Free access to .NET Memory Management video
Everything you need to know about Garbage Collection, Temporary Objects, Fragmentation, Finalization and common causes of memory leaks in .NET. Watch the video here.
Microsoft Visual Studio 2010 Professional
Microsoft Visual Studio 2010 Professional will launch on April 12, but you can beat the rush and secure your copy today by pre-ordering at the affordable estimated retail price of $549 (US). Pre-order now.
Nevron Chart for .NET 2010.1 Now Available
The leading .NET charting control now features PDF, Flash and Silverlight export, visualization of large datasets and more. Deliver true charting functionality to your BI, Scorecard, Presentation or Scientific apps. Download evaluation now.
Developer-Ready ASP.NET 2.0 Web Hosting with 3 MONTHS FREE
Now supporting .NET 3.0 Framework with Windows Workflow Foundation, Windows Communication Foundation (WCF), Windows Presentation Foundation (WPF), windows CardSpace (WCS)! Providing more flexibility for Developers with Web Services Support and a User/Permission Manger. Also supporting MS SQL 2005/2000 with Real-Time Backups, FREE Automated Attach .MDF Tool, FREE SQL Restore and Shrink SQL DB Tools, and SQL
 
   Print Read/Post comments Post a comment  Similar Articles  
   Email to a friend  Bookmark  Author's other articles  
 
 Post a Feedback, Comment, or Question about this article
Subject:  
Comment:  
Become a Sponsor
 Comments

 Hosted by MaximumASP  |  Found a broken link?  |  Contact Us  |  Terms & conditions  |  Privacy Policy  |  Site Map  |  Suggest an Idea  |  Media Kit
Current Version: 5.2009.6.2
 © 2010  contents copyright of their authors. Rest everything copyright Mindcracker. All rights reserved.