Functional. Net 4.0-tuples and zip

Source: Internet
Author: User

Previusly, when covering some of the additions to. net 4.0 framework such as optional and named parameters, some of the other additions have caught my eye from the perspective of functional programming. unlike. net 3.5, this release is not as targeted towards functional programming as it is more towards dynamic programming and COM interoperability. but, there are a few items to note that we can soon take advantage of, including the tuple type and the zip operator function among other items.

Looking at tuples

To define a tuple, it comes from the mathematics field, and is simply an ordered list of values, which are components of that tuple. these components can be of any type, whether it be string, integer, or otherwise. in order to refer to these components, we retrieve references to them by absolute position in that sequence.

In F #, The tuple is a fully supported data type and perhaps one of the most useful. to define a tuple is to define a number of expressions grouped together with comma separation to form a new expression such as the following:

# Light

// Val blogger: string * string
Let blogger1 = "Matthew", "podwysocki"
Let blogger2 = "Jeremy", "Miller"
Let blogger3 = "David", "Laribee"

// Val bloggers:
// (String * string) * (string * string)
Let bloggers = blogger1, blogger2, blogger3

From there, tuples can be decomposed into their components in either of two ways. for pair tuples, a tuple with exactly two components, can be deconstructed using the FST and SND functions such as the following:

# Light

Let pagehitcount = "http://www.codebetter.com/", 25500
Let page = FST pagehitcount
Let hitcount = snd pagehitcount

However, it is more common to use a pattern expression to retrieve values from a tuple, such as the following code:

# Light

Let request =
"Http: // codebetter ",
New datetime (2008, 11, 15 ),
"Firefox/3.0.4 (. net clr 3.5.30729 )"

Let host, date, useragent = request

What we're re able to do is break down the given request into three pieces, the host, date and User-Agent. This makes pattern matching against tuples really powerful such as the following:

# Light

// Val permit_request: string * int-> bool
Let permit_request = Function
| "HTTP", "Google.com", 80-> true
| _, "Microsoft.com", _-> true
| "Ftp", _, 21-> true
| _-> False

Just as well, we cocould even use them in active patterns so that we cocould pattern match against parts of a fileversioninfo in order to determine which action to take such as the following.

# Light

Open System. Diagnostics

Let (| fileversionsections |) (F: fileversioninfo) =
(F. filename, F. productname, F. productversion)
Let parse_files = Function
| Fileversionsections (FN, "parallel extensions for the. NET Framework ",_)
-> Printfn "parallel extensions file % s" FN
| Fileversionsections (FN, "Microsoft Office communicator 2007 ",_)
-> Printfn "communicator file % s" FN
| _-> Printfn "unknown file"

You're saying, great, but what has this to do with. Net 4.0?

Tuples in. Net 4.0

Earlier this month, Justin Van Patten, on the Bcl team blog announced some the base class library changes coming to. Net 4.0. Among them was tuples in which was stated:

We are providing common tuple types in the BCL to facilitate language interoperability and to reduce duplication in the framework. A tuple is a simple generic data structure that holds an ordered set of items of heterogeneous types. tuples are supported natively in ages such as F # And ironpython, but are also easy to use from any. NET language such as C # and VB.

What does that mean exactly? Does this mean we'll get some form of syntactic sugar around them as well? If we coshould decompose them in such a fashion as we do in F #, And to initialize them in an easy fashion without a lot of pomp and circumstance. gazing from the intent in. net libraries, something like this might be an option:

VaR T1 = tuple. Create (1, 'A ');
VaR I1 = t1.item1;
VaR I2 = t1.item2;

But, unless there were a nicer way to tease apart the data, it just becomes a simple holder of data, instead of something that we cocould decompose easily into patterns. I wowould love to some sort of syntactic sugar in C # to allow for this to happen. I am, however, encouraged that they are working with the F # team and other teams to ensure compatibility between the libraries.

If you open reflector, you will find the Type Definitions in mscorlib. dll version 4.0 under the system namespace. you may also be surprised to find them as internal classes only at this point, which is unfortunate and we find ourselves not able to take advantage of these things such as the codecontracts and biginteger/bignumber in. net 3.5 libraries.

 

As you can see from the above screen catpure, we have up to 7 arguments for a given tuple and the rest as defined by another tuple. i, however, haven'tseen tuples quite that large before, but it's always possible...

The zip operator Function

Another functional programming item that has been added to the system. LINQ. enumerable class in system. core. DLL. this method allows us to combine two collections together using a function to calculate the new element given the element from each collection.

In F #, we have two ways of doing this in F # In the seq module. They are defined:

Val MAP2: ('A-> 'B-> 'C)-> seq <'a>-> seq <' B>-> seq <'C>
Val ZIP: seq <'a>-> seq <'B>-> seq <'a *' B>

The MAP2 function takes a function which takes the two items from the list to produce the calculated item, and two collections and returns a new collection of the computed items. if one collection is shorter than the other, the rest of the computations are not completed. the zip function is a simple function which takes the items from the first and second collection and combines them in a tuple.

An example of each follows:

// MAP2
Let L1 = seq [1 .. 26]
Let L2 = seq ['A'... 'Z']
Let mapped = seq. MAP2
(Fun a B-> sprintf "% d % C" a B) L1 L2

// Zip
Let z1 = seq ['A'... 'Z']
Let Z2 = seq ['A'... 'Z']
Let zipped = seq.zip Z1 Z2

Now, to use the C # version is rather simple. The signature of this method is simply:

Public static ienumerable <tresult> zip <tfirst, tsecond, tresult> (
This ienumerable <tfirst> first,
Ienumerable <tsecond> second,
Func <tfirst, tsecond, tresult> func)

As you can see, this follows the same exact pattern as the MAP2 function from F #, which allows us to compose the two items together via a function to compute the hew item. let's define a few tests that will pass given our knowledge of the zip function. we can also include the tuple class, well, at least the F # version to show that behavior as well. these are basically tests that I wrote for my functional C # library, but I hadn't published my tests, and I probably shoshould.

[Fact]
Public void zipwithadding_shouldaddranges ()
{
// Arrange
VaR range1 = enumerable. Range (1, 10 );
VaR range2 = enumerable. Range (11, 10 );

// Act
VaR range3 = range1.zip (range2, (I, j) => I + J );

// Assert
Assert. True (range3.count () = 10 );
Assert. True (range3.elementat (0) = 12 );
Assert. True (range3.elementat (9) = 30 );
}

[Fact]
Public void zipwithintandchar_shouldcombine ()
{
// Arrange
VaR range1 = enumerable. Range (1, 5 );
VaR range2 = new [] {'A', 'B', 'C', 'D', 'E '};

// Act
VaR range3 = range1.zip (range2, (I, j) => I + J. tostring ());

// Assert
Assert. True (range3.count () = 5 );
Assert. True (range3.elementat (0) = "1A ");
Assert. True (range3.elementat (4) = "5E ");
}

[Fact]
Public void zipwithtuples_shouldcombinelists ()
{
// Arrange
VaR range1 = enumerable. Range (1, 5 );
VaR range2 = new [] {'A', 'B', 'C', 'D', 'E '};

// Act
VaR range3 = range1.zip (range2, (I, j) => New tuple <int, char> (I, j ));

// Assert
Assert. True (range3.count () = 5 );
Assert. True (range3.elementat (0). compareto (
New tuple <int, char> (1, 'A') = 0 );
Assert. True (range3.elementat (4). compareto (
New tuple <int, char> (5, 'E') = 0 );
}

Because the parallel extensions. net are becoming part of the Bcl in. net 4.0, The parallelenumerable also has the zip method as well, which allows us to take advantage of data parallelism, shocould our machine allow such as this:

[Fact]
Public void parallelzipwithadding_shouldaddranges ()
{
// Arrange
VaR range1 = parallelenumerable. Range (1, 10 );
VaR range2 = parallelenumerable. Range (11, 10 );

// Act
VaR range3 = range1.zip (range2, (I, j) => I + J );

// Assert
Assert. True (range3.count () = 10 );
Assert. True (range3.elementat (0) = 12 );
Assert. True (range3.elementat (9) = 30 );
}

With the including of the parallel extensions. net, it's going to be a lot of more functional fun built-into the BCl. I can only hope for more of this coming down the road.

Wrapping it up

Although. net Framework 4.0 release didn't give too into items for functional programming as they had in. net 3.5 release,. net 4.0 framework has a few interesting items with the consent of the tuple and zip method. even more intrigue of course comes from adding the parallel extensions for. net Framework to the base class library as a first-class citizen.

I 'd wish they wowould have made the tuple class public already so that we cocould at least play around with some of those features, but I as your understand why some of the decisions were made, and I also realize it's early in the cycle still. hopefully in the next release or so, it will become available to us to use, including some syntactic sugar about their creation and decomposition, but ultimately, that's a language demo-and not necessarily a framework demo.

It's great to see a language convergence in terms of libraries now being available to all. F # will continue to be my language of choice, but with C # gaining some of these libraries, it makes the transition switch much easier without having to reinvent the wheel with either re-implementing the feature or converting func delegates to F # fastfunc types and back again.

This entry was posted in C #, F #, functional programming. Bookmark the permalink. follow any comments here with the RSS feed for this post.

Forbidden. Net code contracts and TDD are complementary

DC alt. Net 11/25-web testing frameworks →

  • Rsenna

    Perhaps I got it wrong.

    But your C # * zip * method represents an implementation of F # * MAP2 * function, right? I'm trying to learn F #, So that got me confused.

    Anyway, the zip function may be seen as a special case of MAP2...

  • Http://podwysocki.codebetter.com/Matthew. podwysocki.

    @ Rsenna

    That is correct, the zip is an implementation of the MAP2 function.

    Matt

  • Http://smellegantcode.wordpress.com/Daniel earwicker

    Where you wrote:

    VaR range3 = range1.zip (range2, (I, j) => New tuple (I, j ));

    You can actually just put:

    VaR range3 = range1.zip (range2, tuple. Create );

    This is because there's a static non-generic helper class with generic overloads of create (for up to 8 ARGs). Neat!

  • Http://codebetter.com/members/Matthew.Podwysocki/default.aspx Matthew. podwysocki.

    @ Daniel,

    You are correct, but this wasn' t there at the time this post was done.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.