|
|
-
When reading data from a SQL database in F#, you have a couple of options. You can use F# implementation of LINQ, which allows you to write queries directly in the F# language or you can use standard ADO.NET classes such as SqlCommand. The second option is often good enough - when you just need to call a simple query, you probably don't want to setup the whole LINQ infrastructure (generate classes, reference F# PowerPack, etc.) Unfortunately, ADO.NET classes are a bit ugly to use. When calling an SQL stored procedure, you need to specify the name of the procedure as a string, you need to add parameters one-by-one by creating instances of SqlParameter, you need to dynamically cast results from the obj type and so on...
In this article, we'll look how to use the dynamic operator to make the experience of using ADO.NET from F# dramatically better. Dynamic operator (there are actually two of them) are a simple way of supporting dynamic invoke in F#. We can use it to write code that looks almost like an ordinary method call or property access, but is resolved dynamically at runtime (using the name of the method or property). The following example shows what we'll be able to write at the end of this article: // Call 'GetProducts' procedure with 'CategoryID' set to 1
use conn = new DynamicSqlConnection(connectionString)
use cmd = conn?GetProducts
cmd?CategoryID <- 1
conn.Open()
// Read all products and print their names
use reader = cmd.ExecuteReader()
while reader.Read() do
printfn "Product: %s" reader?ProductName
If you ever tried to call a SQL stored procedure directly using the SqlCommand, then you can surely appreciate the elegance of this code snippet. Let's now take a look at a larger example and some of the neat tricks that make this possible. [Continue reading...]
|
-
(Note: This article is cross-posted from my blog)
Some time ago, I wrote a couple of examples of developing web applications in F# using ASP.NET. Since then, the F# language and runtime has changed a little bit and there are also new technologies available in ASP.NET, so I thought I'd write a more up-to-date article on this topic. In this article, I'll present a simple "demo" F# web application that you can use as a starting point when creating your own projects (you'll also find a convenient Visual Studio 2010 template below). The article shows the following interesting things:
- ASP.NET MVC - We're going to use ASP.NET MVC Framework to create the web application. As the article name suggests, most of the actual program code including models and controllers will be implemented in F#.
- F# LINQ to SQL - The application uses a sample Northwind database and we'll write queries for selecting data from the database using LINQ support that's available in the F# PowerPack [^].
- F# features - The application also uses some nice F# features that are quite useful for developing web applications. We'll use modules and records to implement the model and we'll also use advanced meta-programming features for constructing LINQ queries.
If you want to use F# for creating an MVC application, you have a few options. It should be possible to create the web application solely as an F# project. However, we'll use a more convenient approach. We'll create a standard C# MVC project and move all the actual implementation to an F# library. We'll look at the application structure shortly. The following screenshot shows a page that lists products in the Northwind database:
Application structure
The most convenient way to create an MVC web application, which is implemented in F# is to mix several C# and F# projects in a single solution. F# doesn't include web project templates and doesn't implement all Visual Studio tools that are needed for comfortable web development, so we'll create a C# projects that allow us to use LINQ to SQL and ASP.NET designers. All important pieces of code will be written in F# though!
- WebApplication is the main MVC web application project. This is a C# project, but it doesn't contain almost any code, because model and all controllers are implemented in a referenced F# library. This project mainly contains views (
aspx files) and other resources (such as stylesheets and database).
- WebApplication.Core is an F# project that implements the core functionality of the application. In the sample application, it contains
Model.fs, which implements the functionality for accessing data and two controllers (HomeController.fs for the main page and ProductsController.fs for working with products database). The Global.fs file registers routes for the URL rewriting.
- WebApplication.Data is a simple C# project that contains only generated LINQ to SQL classes for our sample database. Although it is possible to rewrite the classes to F#, it is more convenient to use the tool available for C# in Visual Studio.
When creating the projects by hand, you'll need to translate the generated controllers from C# to F# and you'll need to add all relevant ASP.NET references to the F# library project (there is an absurd number of them). However, you shouldn't face any difficulties or tricky problems. In any case, it is easier to start using the Visual Studio 2010 template that you can download below.
Now that we looked at the application structure, we'll look at a couple of interesting places in the application. This may give you an idea of some benefits that F# provides to web developers (although the sample is only very basic!)
Implementing model in F# with LINQ
As already mentioned, I decided to use the F# implementation of LINQ to SQL for data access in the application. There are only a few articles about this topic, so we'll discuss it in some more details. As already mentioned, LINQ to SQL cannot generate the classes natively in F#, so I created a separate C# project that contains just the generated classes.
The following listing shows the content of the Model.fs (without a single function that will be discussed shortly). As you can see, I created one record type for storing information about products that will be displayed in the page (we'll use it later). The rest of the model is implemented as an F# module, which means that it will appear as static class to .NET. Modules are quite useful for storing functionality that doesn't need to be encapsulated in a class, so this is a perfect fit: namespace WebApplication.Core
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq
open Microsoft.FSharp.Linq.Query
// Namespace with LINQ to SQL generated classes
open WebApplication.Data
// Stores information about product (will be used later)
type ProductInfo = {
ID : int
Name : string
Category : string
Price : System.Decimal }
// Implementes the model for our MVC application
module Model =
// Returns the 'Product' entity with the given ID
let ProductDetail (id) =
let dx = new NorthwindDataContext()
<@ seq { for p in dx.Products do
if (p.ProductID = id) then yield p }
|> Seq.head @> |> query
The ProductDetail function first creates a new instance of the generated data context and then runs the query. A query in F# is written using quotations. This means that the data-processing code is enclosed in <@ ... @>, which instructs the compiler to store the expression tree of the code (instead of compiling it). The quotation is then passed to the built-in query function that interprets it as a LINQ query.
Inside the query, you can use sequence expressions as well as some basic functions from the Seq module. In our application, we're using sequence expression that selects all products with the specified ID and then use the Seq.head function to get only first such product.
Composing LINQ queries
The second function implemented in the model will return a list of products. I made it a bit more sophisticated to demonstrate some interesting capabilities of the F# support for LINQ. In particular, the function takes a parameter that can specify how to sort the products. The parameter is a quotation that represents the expression tree of a key selector that specifies how products should be sorted. A key selector is a function that takes a product and returns some its property (or even calculated value). For example, to sort products using the length of the product name, the key selector would be <@ fun p -> p.ProductName.Length @>. Let's first look at the code and I'll explain how the key selector is used after that: let ListProducts (keySelector:Expr<Product -> 'T>) =
let dx = new NorthwindDataContext()
<@ seq { for p in dx.Products |> Seq.sortBy %keySelector do
for c in dx.Categories do
if (p.CategoryID.Value = c.CategoryID) then
yield { ID = p.ProductID
Name = p.ProductName
Category = c.CategoryName
Price = p.UnitPrice.Value } } @> |> query
The keySelector parameter has a type Expr<Product -> 'T>, which means that it is an expression tree (or a quotation, in the F# terminology) of some function that takes a Product and returns some value - the function is generic, so the value can be anything. It is used in the quoted expression as a parameter of the Seq.sortBy function. We use %keySelector, which means that the quotation of the key selector will be "spliced" into the quotation we're writing. When we pass the quoted query to the query function later, it will see the actual expression in place of the variable spliced using the % operator. This allows us to compose queries from individual pieces, which is quite useful and cannot be directly done in C# - we can for example dynamically compose the WHERE clause using conditions specified by the user.
The sample query also uses a sequence expression with nested for loops to implement the JOIN functionality. Although this isn't needed, because the Product entity contains a reference to the associated Category, I wrote the join explicitly to demonstrate a more complex LINQ query in F#. Finally, when returning the result using the yield keyword, we construct a value of the record defined in the previous listing (which is a bit simpler than declaring and creating a class in C#).
Implementing controllers in F#
Now that we have the module implementing the model component of our MVC application, we'll also need to implement the controller. We'll look at the content of the ProductsController.fs file, which is more interesting as it uses the model and also calls the ListProducts function with several different key selectors as arguments.
The class contains two members that implement two actions of the controller. The member List loads a list of products from the database. It has a parameter which may be null and specifies the ordering of products (simply as an integer). The second member returns details about the specified product and is named Detail: let (|NonNull|_|) (a:Nullable<_>) =
if a.HasValue then Some(a.Value) else None
type ProductsController() =
inherit Controller()
member x.List(id:Nullable<int>) =
x.ViewData.Model <-
match id with
| NonNull(1) -> Model.ListProducts <@ fun p -> p.UnitPrice.Value @>
| NonNull(2) -> Model.ListProducts <@ fun p -> p.CategoryID.Value @>
| _ -> Model.ListProducts <@ fun p -> p.ProductName @>
x.View()
member x.Detail(id:int) =
x.ViewData.Model <- Model.ProductDetail id
x.View()
The listing first defines a simple active pattern that is useful when working with Nullable<T> values. It matches when the value given as an argument contains some value and fails when the value is empty. We use it in the List member where we need to select the ordering. When the parameter contains 1, we order products by price, parameter 2 specifies ordering by category and in all other cases (including empty value) we use default ordering by the product name. As you can see we specify several different key selectors (functions taking Product enclosed in quotation using <@ ... @>) of various return types. This is possible, because the ListProducts function is generic.
In both of the actions, we assign the result to the Model property of the ViewData. This allows the view to access the model in a type-safe way. The code in the view is standard C# code, so we won't look at it here - it is just worth mentioning that F# records appear as standard .NET classes to the C# code, so the integration is very smooth.
Summary
When developing ASP.NET MVC application in F#, the most convenient thing to do is to create a C# project and move all implementation to an F# library that is then referenced from the C# project (which contains only aspx files and other content related to the presentation layer). In F#, we can use LINQ for accessing data and the fact that quotations can be nicely composed using splicing allows us to implement some patterns that are not easy to write in C#. Moreover, F# features such as modules and records as well as pattern matching are quite useful in web development. However, this article contains only a very basic example that doesn't really take the full advantage of F#, so can only encourage you to download the template below and try experimenting yourself!
Visual Studio 2010 template
As already mentioned, I created a simple template based on the described project that allows you to simply create MVC web applications that use F# by selecting the template in Visual Studio 2010. To increase your appetite, the screenshot on the right is taken from my "New Project" dialog after installing the template. There are two minor gotchas with projects created from the template that you need to go through:
- You'll need to go to the
WebApplication.Data project and generate the LINQ to SQL classes from the database description manually (for some reason, this doesn't happen automatically when you build the project). To do this, right click on Nortwind.dbml and select "Run Custom Tool" command.
- You'll need to fix the reference from
WebApplication.Core to WebApplication.Data - simply remove the existing reference and add it again (choosing the reference to another project in the solution).
Once that's done, you should be able to run the project (assuming that you have SQL Server Express installed - the version that comes with Visual Studio 2010 is fine). In case you don't want a template for Visual Studio, you can also download the sample as a stand-alone solution:
|
-
Now that Visual Studio 2010 Beta 1 is out, it is finally a good time to take a look at one of the (in my opinion) most interesting new features in the new release - the F# language. As all the regular hubFS readers know, F# existed for quite a long time now as Microsoft Research project, but is now becoming a real Microsoft product. Interestingly, F# is still available as a plugin for Visual Studio 2008, so if you want to try it you don't have to install the whole new beta of 2010.
There are already many resources for learning F# including my functional programming overview, which is a Manning Greenpaper for the book Functional Programming for the Real World that I'm writing with Jon Skeet and my four-part F# introduction. There are also some useful links on the official F# web site including some talk recordings. However, I haven't yet seen any good F# webcast focusing mainly on showing F# source code, starting from simple functional concepts to the real-world features like asynchronous workflows and object-oriented programming in F#, so I decided to create one.
(The whole webcast series is available in my other blog and I'm cross-posting the links and brief descriptions of each of the parts here)
The F# development process
The webcast starts by experimenting with F# and by introducing some of the essential functional concepts and then follows the usual F# development process. It starts by creataing an empty F# script (New File... - F# Script File in Visual Studio), which is the easiest way to start coding in F#. We'll just create an empty script, start writing the code and run it interactively to see how it works. This way, we'll develop a very simple F# snippet for downloading content of a RSS feed and for searching for feeds that contain the specified keyword.
Once we have a simple solution to the problem, we can start improving it and refactoring it in various ways. I believe that refactoring is a very important part of the usual F# development process. In particular, we'll see how to wrap the code into asynchronous workflows to make it run asynchronously (rather than using blocking calls) and also potentially in parallel (rather than downloading and processing all the feeds in sequence).
Finally, in the last part of the series, you'll see one more refactoring. We'll wrap the existing code into a simple object oriented library and we'll also finally turn it from a simple F# script file into a standard .NET DLL library that can be used from C#. As you'll see in the webcast, this is again a relatively simple refactoring that includes only a couple of minor changes in the source code. Once we'll compile the library, we'll also look how to use it from C# and in particular, from a simple ASP.NET web application.
Introducing F# webcast
The links to the individual parts of the webcast are available here. Each of the articles also contains link for downloading the video (in case you wanted to view it offline) and also full source code that I wrote during the presentation:
- Part I. - Introducing functional concepts
The first part introduces functional programming principles such as immutability, recursion and functions that take other functions as parameter (higher order functions). This can all be demonstrated in C# 3.0, so we start with C# and then look how the same concepts look in F#. Finally, the first part also shows functions for working with lists in F#.
- Part II. - Using standard .NET libraries
The second part demonstrates how we can use standard .NET libraries. It uses classes from System.Net and System.Xml to download content of a web page (RSS feed), load it into XML document and process it to find only posts that contain some specified keyword.
- Part III. - Downloading web pages asynchronously
The third part shows how to make the code from the part II. better. It introduces F# asynchronous workflows that can be used for writing code that doesn't block a thread when waiting for the completion of some I/O request. This part also shows how to modify the code to download and process multiple feeds in parallel.
- Part IV. - Developing standard .NET libraries
In the fourth part, we look how to encapsulate the functionality written in F# into classes. We'll create a project and we'll wrap the code we wrote into a .NET class. We'll also look how to compile the project into DLL and how to use it from a simple C# web application.
|
-
(This article is based on two articles about the book that I posted to my other blog).
If you’ve been reading my blog or seen some my articles, you know that I’m a big fan of the F# language and functional programming style. I’m also often trying to present a bit different view of C# and LINQ – for me it is interesting mainly because it brings many functional features to a main-stream language and allows using of many of the functional patterns in a real-world. Elegant way for working with data, which is the most commonly used feature of C# 3.0, is just one example of this functional approach. Talking about real-world applications of functional programming, there is also fantastic news about F#. It was announced last year that F# will become fully supported Visual Studio language and the first September CTP version of F# was released recently!
I always thought that the topics mentioned in the previous paragraph are really interesting and that functional programming will continue to become more and more important. That’s why I’m really excited that I have the privilege to write a book about these topics. The book is called Real-world Functional Programming in .NET [^] and it’ll be published by Manning Publications [^]. Even though there are some books about F# already (and more are probably comming soon), I believe that my book is unique in a way that it talks about both C# and F#. This is useful when understanding functional programming concepts, because you can see how would the same thing look in C#. Also, there are many functional techniques that can help you with daily C# programming and these are also discussed in the book. Here is a couple of reasons why you should have this book on your bookshelf:
- Ideas behind C# 3.0 and LINQ - these main-stream technologies are inspired by functional programming and the new C# 3.0 features give us definitely much more than just a new way to query databases. The book explains the ideas behind these features and shows how to use them more efficiently in a wider range of scenarios.
- Learning the F# language - F# is becoming a first-class citizen [^] in the Visual Studio family of languages, which alone would be a good reason for learning it! Even if you're not going to use it for your next large .NET project, you'll find it useful for quick prototyping of ideas and testing how .NET libraries work thanks to the great interactive tools.
- Real world examples - the book includes a large set of real-world examples that show how to develop real .NET applications in a functional way - both in F# and C#. Among other things, the examples show how to utilize multi-core CPUs, how to better obtain and process data and how to implement animations and GUI applications in a functional way.
To summarize, the goal of the book is to explain the key ideas of functional programming to real world .NET developers in a way they can benefit from them. It actually very much follows my personal experience – I started seriously looking at functional programming in the F# language after using primarily C# for quite a long time.
What's new?
Here is a couple of links if you're interested in more information about the book. I started a companion web site for the book, so you'll find everything regarding the book, links to related articles and the source code here: www.functional-programming.net. There is a book page at Manning web site where you can find the direct links to the free content (Chapter 1 and the Greenpaper) and also the option to purchase the book via MEAP today:
The MEAP program allows you to get the book now and start reading chapters as they become available. Once the whole book is completed, you'll get the final version (either electronic or both electronic and printed). This means that you'll be among the first people to see the draft and you also have a chance to influence it. I've been receiving a large number of great suggestions as well as corrections from the MEAP program via book forum at Manning [^], so huge thanks to anyone who is reading the book and discussing it there!
The MEAP version is updated every couple of weeks, so things has changed since I posted the announcement to my blog and I had to rewrite this paragraph. Currently, you can get first 10 chapters and I'm working on chapter 11, so you can see that there is very small delay (when I see some of the errors in the draft that readers report in the forum, I sometimes think that it is almost too small - thanks again)!
About a month ago, the MEAP version of the book was first in the list of Manning bestsellers (even before books on topics like ASP.NET "MVC" and Silverlight, which was a very nice surprise for me)! Click on the image to see the full-size screenshot:
What’s inside?
The most interesting thing for me about writing the book is that I really had to shape my ideas very clearly and find a good way to organize all the topics. One point of view that I found particularly useful (and it reflects how I write code in F#) is that F# gives you a way to start with a very simple, easy to write and clear code and later turn it into a robust .NET code. At the beginning you can write your code just as a script for F# interactive using only the basic functional features. Thanks to the type inference the code is also very succinct. In the later phase you can use features like abstract interface types and object expressions to organize the code and make it easily accessible for example from C#. The nice thing is that the transition is very smooth, so you don't have to rewrite almost any code.
Since many of the functional features are now available in C# 3.0, it is possible to apply some of these ideas to C# too. In particular, we can simplify many object-oriented constructs (including some well known design patterns) and also use many effective functional techniques. This way of thinking is very suitable for a book, because we can start by looking at simple and clear ideas and then learn more sophisticated techniques and language features. The chapters that are currently written follow this organization. Here is a brief overview of the content of every chapter:
Part I. Introduction
To many of the readers, functional programming is a completely new idea. The basic principles of functional programming are also quite different to what you may be used to. The first part of the book (containing chapters 1 - 4) serves as an introduction and touches lightly some of the ideas that will later become essential.
- Chapter 1: Thinking differently about problems starts with a little section about the long history of functional programming (By the way, would you believe that the first functional programming language celebrated its 50 years in 2008?). As a next thing, the chapter discusses some important reasons why functional concepts are important nowadays and shows successful real world applications of these concepts. The largest part is a tasting of what you'll find later in the book and finally, it contains a section showing the first example application in F#.
- Chapter 2: Functional concepts and programming languages introduces the concepts behind functional programming. As I already mentioned many of the functional concepts are different then what you might be used to, so this chapter gives a brief overview (without any details) showing how functional concepts relate and what they mean for the program structure.
- Chapter 3: Meet tuples, lists and functions in F# and C# finally shows some real functional code. In this chapter, we use both C# and F# when writing any code, which makes it easier to understand what the functional program does. It demonstrates some basic data types used in F# (such as tuples and lists) and also shows how they can be implemented in C#. This chapter also introduces the idea of using functions as values, which is one of the key functional concepts.
- Chapter 4: Exploring F# and .NET libraries by example presents the first real world application implemented in F# and shows how to use various .NET and F# libraries from the F# language. We look at an application that loads data from a file and presents them in a graphical form using a pie chart. This chapter finishes the introductory part by presenting the F# language by example, using only basic features from Chapter 3.
Part II. Core functional techniques
The second part starts describing the "iterative development style" enabled by functional programming in F#. It discusses elementary ways used to construct functional programs. These give us a very clear and concise way to think about problems. Finally, in the later chapters it talks about functional applications from a higher perspective focusing more on architectural acpects.
- Chapter 5: Creating and using common functional values - in functional programming, applications are described more like calculations that take some values as arguments and return a value as a result. This chapter explains what values actually are and talks about usual ways to construct them. This includes representing multiple values, alternative values and also functions (which are values too).
- Chapter 6: Working with values using high-order functions introduces better way for working with basic values from Chapter 5. Instead of manipulating with them directly, we can factor out the changing part of some common operation and then use the single function for many varying tasks. This talks mainly about using functions as arguments, which is also very important for C# 3.0, which supports lambda functions.
- Chapter 7: Designing data-centric programs - when designing an application in the functional style, we start by thinking about the data that it works with. This principle is very useful and clear independently of the language that you're actually using. In this chapter, we demonstrate this principle and also show how it relates to some well-known structural design patterns.
- Chapter 8: Designing behavior-centric programs - not all applications are primarily focused at working with data as described in Chapter 7. Here we talk about the second types of applications. Using functional terminology, this chapter talks about functions in detail. In the object oriented terminology, we look at some behavioral design patterns like Strategy or Command.
Part III.
This section focuses on more advanced concepts that are used later in the "iterative development style". Once the application or a library grows larger, we want to use various .NET facilities to organize it intuitively, expose it to other .NET languages and document it. If the library is intended only for F# then we can leverage of some advanced F# features. Finally, we also want to make the code more efficient by using general functional and F# specific optimization techniques.
- Chapter 9: Turning values into F# object types with members shows how to mix object-oriented and functional style of programming in F#. It shows how the functional concepts (like immutability) can be used well together with object oriented features like encapsulation and how the conceptually simple ideas from Chapter 7 and 8 can be wrapped into real-world .NET code.
- Chapter 10: Efficiency of data structures, tail-recursion and continuations - in the earlier chapters we talked about recursion and data structures such as lists or trees. In this chapter, we look how to use them efficiently. This means how to avoid stack overflow errors when writing functional code and how to write fast code that processes lists and other collections.
- Chapter 11: Refactoring functional programs and using lazy values Refactoring is a phase of development where we try to improve our code without doing any changes in its behavior. This is a very important step and functional programming gives us great tools to do it. Function values are useful when removing code duplication and thanks to immutablity it is much easier to ensure that a change will not affect the behavior. Finally, lazy values allow us to delay some computations until their results are actually needed, which is a topic very close to refactoring.
These are all the chapters that I wrote already (Chapter 11 is not available yet, but I already know quite well what will be inside). I'll definitely blog about more chapters as I'll write them, so stay tuned for another update!
Looking for your feedback!
The book is still "work in progress", so I'm very glad to receive any feedback. I already got many useful comments and suggestions via the book forum at Manning [^], from the reviewers of the first third of the book and also from my colleagues and friends. However, this is probably the first book about functional programming that aims to a very wide audience of .NET programmers, requiring only advanced C# background, so any comments are more than welcome! You can post them to the forum mentioned above as well as directly to me at tomas@tomasp.net.
More information
|
-
(This article is cross-posted from http://tomasp.net/articles/aspnet-in-fsharp.aspx)
As I mentioned earlier, I spent three months as an intern in Microsoft Research in Cambridge last year and I was working with Don Syme and James Margetson from the F# team. Most of the time I was working on the F# Web Toolkit, which I introduced on the blog some time ago [1], but I also worked on a few additions that are now part of the F# release. Probably the most useful addition is a new implementation of the CodeDOM provider for the F# language which makes it possible to use ASP.NET smoothly from F# (but it can be used in some other scenarios as well) together with two ASP.NET sample applications that you can explore and use as a basis for your web sites. This was actually a part of the distribution for a few months now (I of course wanted to write this article much earlier...), so you may have already noticed, but anyway, I'd still like to write down a short description of these ASP.NET samples and also a few tips for those who're interested in writing web applications in F#.
F# and ASP.NET
Let's start by looking at the ASP.NET examples. You can find them in the samples directory in your F# installation under the Web/ASP.NET path. The directory also contains html files with description of the projects and a guide to configuring them, but I'll describe both of these topics in this post. The distribution contains two sample projects:
- AspNetIntro - this project is (almost) the simples possible F# web site, so it can be used as a template for your web sites. It shows how to configure the CodeDOM provider, how to write a simple page with code-behind and how to use the
App_Code directory and data-binding.
- PersonalWebSite - this is a more complex web site ported from the C# sample called Personal Web Site Starter Kit [2]. It demonstrates many of the standard ASP.NET 2.0 techniques including data access controls, master pages, membership and custom HTTP handlers.
ASP.NET Introduction using F#
To start playing with ASP.NET you'll need to open the project (I recommend copying it to your working directory first). If you're using Visual Studio, you can select File - Open - Web Site... in the menu and select the directory with your project as demonstrated at Figure 1 below. The organization of ASP.NET projects is different than organization of ordinary F# projects - in ASP.NET the project is just a directory and it contains all the files in the directory (this is also the reason why you have to open it using a different command). The Figure 2 shows how the files of the ASP.NET Introduction project are organized in the Solution Explorer:
 Figure 1: Open Web Site
 Figure 2: Solution Explorer
As you can see, there are 6 files in the project. The Default.aspx.fs and Default.aspx together form one web page and the DataBinding.aspx.fs with DataBinding.aspx form the second web page. The App_Code directory contains application logic that can be used from other pages in the project and in our sample project it contains only one file (logic.fs). Finally, the web.config file contains configuration of the whole application.
Before we look at the pages you may want to check the web.config file, because it needs to contain the correct reference to the CodeDOM provider implementation including a version of the current F# installation. At the time of writing this article, the latest version is 1.9.3.14, but if you're not sure what version you are using, you can just start the fsi.exe from the F# installation which prints the version number. The web.config file is an xml file and it should contain the following content (with the right version number). The samples in the distribution should contain the correct version number, but the incorrect configuration is a common issue when working with ASP.NET in F#, so it is useful to know what the configuration should look like: <?xml version="1.0"?>
<configuration><system.web>
<compilation debug="true">
<compilers>
<compiler
language="F#;f#;fs;fsharp" extension=".fs"
type="Microsoft.FSharp.Compiler.CodeDom.FSharpAspNetCodeProvider,
FSharp.Compiler.CodeDom, Version=<strong style="color:red;">1.9.3.14</strong>,
Culture=neutral, PublicKeyToken=a19089b1c74d0809"/>
</compilers>
</compilation></system.web>
</configuration>
Now, let's look at the Default.aspx and Default.aspx.fs files that together represent a simple page. The page contains one button and one label (a control that can display some text) and when the user clicks on the button, the result of some calculation is displayed in the label (the calculation is executed on the server-side). The following code is a (slightly simplified) content of the Default.aspx file, which defines the HTML markup together with the ASP.NET controls that are on the page: <%@ Page Language="F#"
CodeFile="Default.aspx.fs" Inherits="FSharpWeb.Default" %>
<html>
<body><form runat="server">
<asp:Button
ID="btnTest" RunAt="server" Text="Click me!"
OnClick="ButtonClicked" /><br />
<asp:Label ID="lblResult" RunAt="server" />
</form></body>
</html>
You can easily identify two server-side controls, because these are written using prefix asp and also contain the RunAt="server" attribute, which means that the control is processed on the server-side. You can use standard HTML notation for setting attributes of the controls. We set the ID attribute to both of the controls, which is important because it allows us to use them in the code-behind code. The OnClick attribute of the button sets an event handler - a member of the FSharpWeb.Default type from the code-behind file that will be called on the server-side, when a user clicks on the button (which submits the HTML form and causes a page reload, so the event can be processed on the server). The file also contains the first special line, which tells the ASP.NET engine that the page is written in F# and it also tells what source file contains the code-behind code and what is the name of type declared in that file. The code-behind file (Default.aspx.fs) has the following content: #light
namespace FSharpWeb
open System
open System.Web
open System.Web.UI.WebControls
type Default() =
inherit Page()
[<DefaultValue>]
val mutable btnTest : Button
[<DefaultValue>]
val mutable lblResult : Label
member this.ButtonClicked(sender, e) =
this.lblResult.Text <-
(sprintf "Factorial of 5 is: %d"
(FSharpWeb.Logic.factorial 5))
As we can see, the file contains an F# object type (named Default), inherited from the base ASP.NET Page type. Thanks to the recent improvements in F# it is possible to write the type using the new implicit class syntax (note the parentheses after the type name), which means that you can place additional initialization code to the type declaration directly (following the inherit clause and F# will treat this as a constructor.
The class contains a mutable field for every control declared in the declarative markup with the name same as the ID attribute in the markup file (btnTest and lblResult). The ASP.NET initializes these controls automatically when it creates the page (that's why the fields are marked using mutable), so we don't need to initialize these fields in our code - F# doesn't usually allow uninitialized fields, but if you place the DefaultValue before the field declaration, it will be initialized to the default value (null), which is correct, because the field will be later initialized by the ASP.NET runtime. Finally, the type contains a member called ButtonClicked, which is a same name we used in the markup for the OnClick attribute of the button control. This is an event handler that will be called when user clicks on the button, it performs some calculation (the factorial function is declared in the logic.fs file) and sets a property of the other control that we have on the page.
Personal Web Site in F#
 Figure 3: Personal Web Site
The second sample ASP.NET project is a port of quite a complex ASP.NET web site which also uses MS SQL database. The database can be created manually as described in Welcome.html in the PersonalWebSite directory, but I also uploaded the database to my web, so you can just download it and attach it in the SQL server (this is described below and the files for download can be found at the end of the article). The PWS_AspNetDb is a database managed by ASP.NET that contains user information - the database below already contains the required role (called Administrators) and one user (admin with password admin123!). The second database file (PWS_WebPersonal) contains the application data, mainly information about photos and galleries (as you can see from the screenshot in Figure 3).
The application uses many advanced ASP.NET features including the following:
- Master Pages - the overall structure of the web site is stored in a master page (
Default.master) and the other pages use the asp:Content control to fill the place holders in the master page.
- Site Maps - the map of the web site is defined in the
web.sitemap file and is used for generating the menu in the Default.master file.
- Themes - the design of the page including CSS files and images are managed using ASP.NET Themes - there are two standard themes in the
App_Themes directory.
- Membership - the web uses standard ASP.NET technology for managing user accounts including the controls for manipulating with users (e.g.
asp:CreateUserWizard control is used in Register.aspx file).
- Data Controls - ASP.NET data-access controls are used for reading the data from the application logic layer (implemented as a module in F#)
Configuring the databases
To configure the databases required by the demo, you can either follow the steps described in the Welcome.html file (which is part of the sample project), or if you already have some version of SQL Server installed on your machine, you can download the sample databases below (a bunch of MDF and LDF files) and attach them to the SQL Server. I'll explain how to do this using full version of SQL Server, but the steps needed with Express edition are very similar.
Once you downloaded the files, you'll need to launch SQL Server Management Studio and connect to the server instance. After doing that you should see an "Object Explorer" window, where you can right click on the "Databases" group and select "Attach..." from the pop-up menu. In the opened dialog window, you can add the databases (by selecting the MDF file) and click the "OK" button to attach the databases. Finally, you'll need to modify the web.config file in the Personal WebSite sample to include the following section: <connectionStrings>
<add name="Personal" providerName="System.Data.SqlClient" connectionString=
"Data Source=.;Integrated Security=True;Database=PWS_WebPersonal" />
<remove name="LocalSqlServer"/>
<add name="LocalSqlServer" connectionString=
"Data Source=.;Integrated Security=True;Database=PWS_AspNetDb" />
</connectionStrings>
The Data Source parameter in the connection string specifies the instance of the SQL Server, where the databases are attached. By default this is the name of your computer (which can be written shortly using dot "."). When using the SQL Express the default instance name is ".\SQLExpress". The Database parameter specifies the name of the database, which you can see in the "Object Explorer" in the SQL Server Management Studio. After following these steps, you should be able to run the demo application.
Data-access in F#
Most of the ASP.NET technologies used in the web site are used in almost the same way as in C#, so I will not discuss them in larger details, but the last item in the list - the use of ASP.NET data controls together with F# is I believe quite interesting, so I'll write a few notes about it. Let's look for example at the Photos.aspx file, which displays a list of photos in a gallery. The most important parts of the file related to data access are shown in the following code snippet: <asp:DataList RunAt="server" DataSourceID="photoSource" EnableViewState="false">
<ItemTemplate>
<!-- ... -->
<a href='Details.aspx?AlbumID=<%# base.Eval("PhotoAlbumID") %>'>
<img src="Handler.ashx?PhotoID=<%# base.Eval("PhotoID") %>&Size=S"
class="photo_198" style="border:4px solid white"
alt='Thumbnail of Photo Number <%# base.Eval("PhotoID") %>' />
</a>
<!-- ... -->
</ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="photoSource" RunAt="server"
TypeName="PersonalWebSite.PhotoManager"
SelectMethod="GetPhotos">
<SelectParameters>
<asp:QueryStringParameter Name="AlbumID" Type="Int32"
QueryStringField="albumID" DefaultValue="0"/>
</SelectParameters>
</asp:ObjectDataSource>
The first ASP.NET control used in the code is asp:DataList, which is a control that simply displays a collection of some items and uses a specified ItemTemplate for displaying every single item. In our case we're working with collection of records and the record has several members (including PhotoID and PhotoAlbumID). To display a value of a record member in the ASP.NET page we have to use ASP.NET Eval method as you can see in the sample. The Eval method reads the specified member of the item in collection and writing the code in <%# ... %> tells ASP.NET that we want to render the result of the expression as a part of the item template. The record that we're using in this example is very simple and has the following structure: type Photo =
{ PhotoID:int;
PhotoAlbumID:int;
PhotoCaption:string; }
This is actually one of the places where the F# version is shorter, because in C# version you have to write this as a class with properties, which makes the code quite longer.
The second server-side control (asp:ObjectDataSource) in the first code snippet isn't visual, which means that it will not produce any HTML output. It serves just as a declarative data-source for the data list and the properties of this control specify how the content for the data list should be loaded. There are various other data-source controls in ASP.NET (e.g. asp:SqlDataSource which loads data directly from the database), but the one that we're using in the example uses a specified .NET/F# type and calls a method of the given object when it needs to retrieve the data. In F# this is even easier, because we can use a name of the module and the code that retrieves the data can be a function in the module.
As you can see the property TypeName is set to PersonalWebSite.PhotoManager, which can be treated as a module called PhotoManager in a namespace PersonalWebSite and the SelectMethod property, which specifies a name of the function that will be called when loading the data is set to GetPhotos. Finally, the SelectParameters specifies that the function expects one argument called AlbumID and that the value of this argument should be retrieved from the query string (that is from the URL of form photo.aspx?albumIdD=42).
Now it is pretty easy to implement the module that matches this specifications and can be used as a data source (we could of course use FLinq for loading the data, but I wanted to keep things simple for now, so we're using standard SqlDataReader object from .NET): namespace PersonalWebSite
// ...
module PhotoManager =
// Function will be called by ASP.NET when loading data
// for the asp:DataList control in the 'Photos.aspx' page
let GetPhotos (albumID:int) =
// Open connection & create command
use conn = new SqlConnection(" ... ")
use cmd = new SqlCommand("GetPhotos", conn)
// Can the user see 'private' photos?
let usr = HttpContext.Current.User
let filter = not (usr.IsInRole("Friends") || usr.IsInRole("Administrators"))
cmd.CommandType <- CommandType.StoredProcedure)
cmd.Parameters.Add(SqlParameter("@AlbumID", albumID)) |> ignore
command.Parameters.Add(SqlParameter("@IsPublic", filter)) |> ignore
conn.Open()
// Read all photos into a .NET ResizeArray type
let list = new ResizeArray<_>()
use reader = command.ExecuteReader()
while (reader.Read()) do
list.Add({ PhotoID = unbox (reader.get_Item("PhotoID"))
PhotoAlbumID = unbox (reader.get_Item("AlbumID"))
PhotoCaption = unbox (reader.get_Item("Caption")) })
// Return the created collection
list
I hope this article explained some of the interesting things that you may find in the ASP.NET samples provided with the F# distribution and I think that the Personal WebSite Sample shows that F# can be used for writing quite complicated web applications as well. Of course, my initial motivation for writing web applications in F# is the possibility of using meta-programming to develop client-side code (the code that runs on the client as a JavaScript) in F# too, which makes development of modern "Ajax"-style applications easier, so if you're interested in this project you may want to look at F# Web Tools [1].
Downloads & References
|
-
In my bachelor thesis I included a short introduction that covered all of the important aspects of the F# programming language and I thought that it may be useful to extend it a little bit to cover also a topics that were not important for my thesis and post it as an article, so there is one and relatively short article that introduces all the interesting F# features. The article got however a bit longer than I expected, so I decided to split it into a three parts that would introduce three different paradigms that are supported by F#. Of course, this series won’t teach you everything about F#, but it tries to cover the main F# design goals and (hopefully) presents all the features that make F# interesting and worth learning. In this first part I will shortly introduce F# and the supported paradigms that will be discussed in the upcoming articles.
Introducing F#
In one of the papers about F#, the F# designers gave the following description: "F# is a multi-paradigm .NET language explicitly designed to be an ML suited to the .NET environment. It is rooted in the Core ML design and in particular has a core language largely compatible with OCaml". In other words this means that the syntax of the F# language is similar to ML or OCaml (don’t worry if you don’t know these languages, we’ll look at some examples shortly), but the F# language targets .NET Framework, which means that it can natively work with other .NET components and also that it contains several language extensions to allow smooth integration with the .NET object system.
Another important aspect mentioned in this description is that F# is multi-paradigm language. This means that it tries to take the best from many programming languages from very different worlds. The first paradigm is functional programming (the languages that largely influenced the design of F# in this area are ML, OCaml and other), which has a very long tradition and is becoming more important lately for some very appealing properties, including the fact that functional code tends to be easier to test and paralellize and is also extensible in a ways where object oriented code makes extending difficult.
The second paradigm is widely adopted object oriented programming, which enables interoperability with other .NET languages. In F# it is often used for implementing elementary data types (meaning that the operations on the type are well known and change very rarely), for grouping a set of elementary functions that are together used to perform some complicated operation (i.e. implementing an interface) and also when working with object oriented user interface frameworks.
Finally, the third paradigm supported by F# is language oriented programming (the design of F# in this area is largely influenced by ML, Haskell and also by LINQ). In general, language oriented programming is focused on developing executors for some code which has a structure of a language (be it a declarative language like XML, or a fully powerful language like some subset of F#). In this overview, I will focus on two techniques provided by F# that allow you to give a different meaning to a blocks of F# code. In a programming language theory, this is often called internal domain specific languages, because the code is written in the host language, but is specifically designed as a way for solving problems from some specific domain. An example of such language (and an associated executor) is a block of code that is written as a linear code, but is executed asynchronously (in F# this can be implemented using computation expressions), or a query that is written in F#, but is executed as a SQL code by some database server (this can be implemented using F# quotations).
F# Overview - Links
In the rest of this article series we will look at all these three paradigms supported by F# starting with functional programming and basic F# types used when writing code in a functional way, continuing with object oriented programming and the support for .NET interoperability which is closely related to the OOP in F#. Lastly, we will look at the language oriented programming paradigm including some of the most important .NET and F# library functions that make it possible. The rest of the articles from the series are available in my other blog:
Other F# Resources
There are many other places where you can find useful information about F#. First of all, there is an official F# web site [1] where you can find the language specification, documentation and other useful resources. There are also two books written about F# (one already published [2], second will be available soon [3]). Lastly, there are also a lot of community resources including an F# community web site with discussion board [4], wiki [5] and several blogs [6,7,8,9]. Finally, there are also some projects developed by the F# community that are available at CodePlex - the first one includes various F# code samples [9, 10] and the second is based on my thesis and tries to solve several web development problems [11].
|
-
My last post at the hubFS was an article that I wrote earlier to my personal blog and I wrote one more article some time ago that is related to F# and I wasn't posted here. The article is a part of a short series that discusses how the same LINQ-related problem can be solved in F# and in C# 3.0 (and in fact, my implementation of the C# version was largely motivated by the F# solution). Because I think that the articles are closely related, I'll write just a short summary here and add links to both articles available in my other blog.
The articles deal with a problem how can one build a LINQ (database) query at runtime. A typical example of a query that developers want to build at runtime is a query where the user can modify the filtering condition (where clause) - for example the application may want to allow combining several conditions, like c.Country == <entered value> with c.Name.StartsWith(<entered value>). In addition you may want to allow combining these single conditions using various operators (at least or and and).
The article about the F# version also shortly introduces the F# comprehensions and quotations that are used when writing LINQ queries using F#. Then it gives a few examples of using LINQ for database queries and finally, it fully describes the example that is shortly introduced below. In the article about the C# version, I described several extensions that are very useful when writing the queries in the F#-style as well as a solution that I use to allow a mechanism similar to F# holes (that are shortly introduced below). Finally, the F# article also contains a version of the FLINQ sample that is compatible with Visual Studio 2008 Beta 2.
Building LINQ Queries at Runtime in F#
In F#, the queries are represented using quotations which can be easily combined thanks to the support for holes (written as underscore). The following example first defines two basic conditions (one of them always returns true and the second returns false). Later, we define two combinators for combining conditions using || and && operators. Finally, we build a condition that is composed from several elementary conditions (stored in a dictionary called dict). To do this we can use the Fold function which takes an initial condition and combines it with all the conditions in the dictionary: // Basic conditions that always return true/false
let falseCond = « fun (c:Customer) -> false »
let trueCond = « fun (c:Customer) -> true »
// Condition combinators
let (||*) f g = « fun (c:Customer) -> (_ c) || (_ c) » f g
let (&&*) f g = « fun (c:Customer) -> (_ c) && (_ c) » f g
// Which combinator will we use?
let (^^) = if generateOr then (||*) else (&&*)
// Build the expression by folding all items in a dictionary
let expr =
dict.Fold(fun key propSelector e ->
Console.Write("Enter value for '{0}':\n> ", key);
let enteredVal = Console.ReadLine();
let currentCond =
« fun (c:Customer) -> ((_ c):string).IndexOf(_:string) <> -1 »
propSelector « §enteredVal »
(currentExpr ^^ e))
(if generateOr then falseCond else trueCond)
Building LINQ Queries at Runtime in C#
In C# the representation of the lambda expression can be either a delegate (Func<...>) or an expression tree (Expression<Func<...>>) and the decision whether to generate a delegate or an expression tree depends on the expected type, which means that the code needs to define a type alias. This is possible thanks to the using statement (though this can be avoided by using helper functions, but in this example I'll instead use aliases). Primitive conditions are easy to define once we have a type alias CustomerCondition (which stands for an expression tree of a lambda expression taking a Customer as an argument and returning a bool). When defining a combinators, we need a way for calling an expression tree in another expression tree and this is done by the method Expand (which is not part of LINQ and is further discussed in the article). Finally, the code that generates the result uses similar technique as the previous F# version: // Basic conditions that always return true/false
CustomerCondition trueCond = (c) => true;
CustomerCondition falseCond = (c) => false;
// Condition combinators
CustomerConditionCombinator combineOr =
(f, g) => (c) => f.Expand(c) || g.Expand(c);
CustomerConditionCombinator combineAnd =
(f, g) => (c) => f.Expand(c) && g.Expand(c);
// Which combinator will we use?
CustomerConditionCombinator combinator =
generateOr ? combineOr : combineAnd;
// Build the expression by folding all items in a dictionary
var expr = dict.Fold((e, item) => {
Console.Write("Enter value for '{0}':\n> ", item.Key);
string enteredVal = Console.ReadLine();
CustomerPropSelector propSelector = item.Value;
CustomerCondition currentCond = (c) =>
propSelector.Expand(c).IndexOf(enteredVal) != -1;
return combinator(e, currentCond);
}, generateOr ? falseCond : trueCond);
|
-
The project that I'm going to introduce in this article has been public for some time already, but I wrote about it only on my personal web site and didn't post the article to the hubFS, which is what I usually do with my other F# articles, so some of the hubFS readers may have missed it. (Cross-posted from: http://tomasp.net/articles/fswebtools-intro.aspx)
I started thinking about working on "Ajax" framework quite a long time ago - the key thing I really wanted from the beginning was using the same language for writing both client and server side code and the integration between these two sides, so you could write an event handler and specify if it should be executed on the client or on the server side. About a year ago I visited Cambridge (thanks to the MVP program) and I had a chance to talk with Don Syme [^]. Don showed me a few things in F# and suggested using F# for this project, so when I was later selected to do an internship at MSR, this was one of the projects that I wanted to work on.
The original reason for using F# was its support for meta-programming ([8], which makes it extremely easy to translate part of the page code-behind code to JavaScript. During my internship, the F# team was also working on a feature called computational expressions, which proved to be extremely useful for the F# Web Tools as well - I bet you'll hear a lot about this from Don soon, so I'll describe only the aspects that are important for this project. Aside from these two key features that F# has, I also quite enjoyed programming in F# itself - I already used it for a few things during the last year, but I could finally work on a large project in F# (and discuss the solution with the real experts!) and I don't believe I would be able to finish the project of similar complexity during less than three months in any other language (but this is a different topic, which deserves separate blog post).
What makes "Ajax" difficult?
Traditional "Ajax" application consists of the server-side code and the client-side part written in JavaScript (the more dynamicity you want, the larger JS files you have to write), which exchanges some data with the server-side code using XmlHttpRequest, typically in JSON format. I think this approach has 3 main problems, which we tried to solve in F# Web Tools. There are a few projects that try to solve some of them already - the most interesting projects are Volta from Microsoft [1], Links language [3] from the University of Edinburgh and Google Web Toolkit [2], but none of the projects solve all three problems at once.
1. Limited client-side environment
First of the problems with "Ajax" style applications is that significant part of the application runs on the client-side (in a web browser). Currently majority of the web applications use JavaScript to execute code in the browser, so in the F# Web Tools we wanted to use JavaScript as well, however in the future, when installation of Silverlight [4] becomes more common, we would like to allow using Silverlight as an alternative.
F# Web Tools allows you to write client-side code in F# (so if you don't know JavaScript, you don't have to learn it!) and also use your existing knowledge of .NET and F# classes and functions (so you can use some of the .NET and F# types when writing client-side code). The code you write in F# is of course executed in JavaScript, so it runs in any browser that supports JavaScript - the current implementation is tested with IE and Firefox, but it could be easily tested with other browsers.
2. Discontinuity between server and client side
The second major problem with "Ajax" applications is that the web application has to be written as two separate parts - client-side part (when written in JavaScript) consists of several JS files and the server-side part (for example in ASP.NET) is written as a set of ASPX and C# or VB files. Also when using JavaScript, both sides use different formats to store the data, so bridging this gap is difficult. In Silverlight [4] (or in GWT [2]), the gap is still there, even though both parts are written using the same technology - the client-side part is usually even a separate project.
In F# Web Tools we wanted to make this discontinuity as small as possible - You can write both server and client-side code in a same file (as a code-behind code). You can also call server-side functions from the client-side code and you can use certain data-types (including your own) in both sides and you can send them as an arguments from one side to the other. What's also important is that these calls are done without blocking the browser, but without the usual cumbersome programming style (calling a function, setting a callback and writing the rest of the code in the callback).
3. Components in web frameworks are only server-side
The third key problem appears once we tightly integrate client and server side code, because there is one more step that has to be done - most of the web frameworks have some way for composing web site from smaller pieces (in ASP.NET this is done using controls) and by defining the interaction between these pieces, however they allow defining the interaction only for the server-side, which is rather problematic in "Ajax" applications, where most of the interaction between components is done on the client-side.
Since F# Web Tools is built using ASP.NET, we wanted to allow same compositionality as ASP.NET - to achieve this, controls written using F# Web Tools can wrap both server and client side functionality. Controls than expose both server and client side properties and events that can be used by the page to implement server-side, respectively client-side interaction between components.
Example - "Ajax" dictionary
I will demonstrate some of the F# Web Tools features using an "Ajax" dictionary application (see screenshot on the right side) which displays possible matching words as you type the word you want to find. This is one of the typical "Ajax" tasks, so it's a good example to start with. First, we need to define the code-behind file for the ASP.NET page - the page itself is quite simple, it contains just two controls - textbox for entering word that you're looking for (txtInput) and generic element for displaying results (ctlOutput), so let's look at the code-behind: // F# record type, which will be used for sending lookup
// results from the server-side to the client-side
type SearchResult = { English:string; Other:string; }
// Code-behind type for the ASP.NET page
[<MixedSide>]
type Suggest =
inherit ClientPage as base
// Controls for entering text and displaying result
val mutable txtInput : TextBox
val mutable ctlOutput : Element
(* .. interaction of components will go here .. *)
Aside from the code-behind class, we also defined a type (SearchResult), which will be used for returning loaded results from server to the client side - it is just a F# record containing two strings (word in English and word in the language we're translating to). Now let's look at the methods that define the interaction logic. The first method that we will look at is a method running on the server-side that takes entered text as an argument and returns a collection of results (ResizeArray<SearchResult>) - it is a static method, so it can't modify anything else on the page (I will write about non-static methods in one of the next articles): // Searches the dictionary for specified prefix
static member LoadSuggestions(prefix) =
server
{ let db = DictionaryDb(connectionString)
let res =
SQL <@ { for p in §db.Dictionary
when p.English.StartsWith(§prefix)
-> {English=p.English; Other=p.Other} }
|> truncate 10 @>
return (new ResizeArray<_>(res)) }
The method is all wrapped in server computational expression (this is one of the new F# features - it will be in details described in the Expert F# [6] book, but I'll definitely write a few lines about it as well) - for now you can read it as (almost) ordinary F# code wrapped in a block that specifies how the code should be executed. The server block is executed as ordinary F# code, but wrapping the code in this block allows us to call it from the client side later. The server block also changes the type of the method, so it doesn't return ResizeArray<SearchInfo>, but Server<ResizeArray<SearchInfo>>, where the Server type helps to ensure that the code will be executed only on the correct side.
Now, let's look at the members that define client-side interaction. The entry point on the client-side is a method called Client_Load, which is executed when the page is loaded in the browser: /// Initialization on the client side - attach event handlers
[<ReflectedDefinition>]
member this.Client_Load(sender, e) =
client
{ do this.txtInput.ClientKeyUp.AddClient(this.UpdateSuggestions) }
In this case we just register an event handler that will be called whenever user types something to the txtInput textbox. It is important to note that this code will be executed in JavaScript - even though when writing it, it is easy to forget about this! You can see the method that is used as an event handler in the next code sample (this whole method will be executed in JS as well): [<ReflectedDefinition>]
member this.UpdateSuggestions(sender, e) =
client
{ do! asyncExecute
(client_async
{ let sprefix = this.txtInput.Text
let! sugs = serverExecute(Suggest.LoadSuggestions(sprefix))
do! this.DisplayResponse(sugs) }) }
If you look at the method, you can see that it contains call to the asyncExecute function and the argument given to the function is entire block of F# code marked using client_async computational expression. The asyncExecute function executes the given block asynchronously, which means that it doesn't block the calling function (and it doesn't block browser GUI) - you can look at it as if it created new thread (but it's actually using one trick from functional programming called continuation passing style, because JavaScript doesn't support threads). In the client_async block, we first read the value from the textbox and then call the LoadSuggestions static method to get collection with matching words. The call to the server-side functions is done using serverExecute function (which is a special function, because it bridges the gap between client and the server automatically). Once we get the result we can call the DisplayResponse method to display the results. You can see that we used a let! and do! instead of let and do here - this is because we're calling a methods that are written using F# computational expressions (server or client blocks). In general when you're calling any ordinary code, you can use the operators without the exclamation mark, but when calling a code wrapped in a block you have to use let! or do!. [<ReflectedDefinition>]
member this.DisplayResponse (sugs:ResizeArray<Result>) =
client
{ let sb = StringBuilder()
let array = sugs.ToArray()
do Array.iter (fun (res) ->
sb.Append("<li><strong>" + r.Source +
"</strong> - " + r.Target + "</li>") |> ignore)
do this.ctlOutput.InnerHtml <- "<ul>" + (sb.ToString()) + "<ul>" }
In this last sample code, we just generate HTML code from the data we received from the server and display them. It is interesting to note, that the code is running on the client-side (it's wrapped in the client block), but you can still use some F#/.NET types and functions in the code (we're using ResizeArray, StringBuilder classes and Array.iter function). This is possible because F# Web Tools re-implements subset of the F#/.NET functionality for the client-side code. And that's all - I described slightly simplified version of one of the F# Web Tools demos, but you can get the full source code if you check out our CodePlex project. You can also look at the live Dictionary sample [^].
More information
I think this example gives you a general idea what is the F# Web Tools and why it is interesting. I will definitely write more about it in the future, because I didn't describe all important features in this example. If you're interested in this project, you can also read the Paper we submitted to the ML Workshop or slides from the presentation I did at the end of my internship in MSR Cambridge (see below). This project is also available to the community at CodePlex, so you can look at the source code (including two more samples).
Related projects and links
|
-
The growth of computer CPU speed is slowly being replaced by the growth of number of CPUs (or cores) in the computer at least for the close future. This causes a revolution in the way software is written, because traditional and most widely used way of writing concurrent applications using threads is difficult and brings several serious issues. Some predictions say that within a few years, almost every computer will have about 16 cores, so there is a huge need for programming paradigms or idioms that help developers write concurrent software easily (see also The Free Lunch Is Over [^] written by Herb Sutter).
Functional programming languages (especially pure functional languages) are interesting from this point of view, because the program doesn't have side-effects which makes it very easy to parallelize it (programs in pure functional languages can't have any side-effects by design, in other functional languages like F# the side-effects can be eliminated by following functional programming style).
Finding primes example
Let's say I want to find all prime numbers between 1 million and 1.1 million (this is example of an operation that can be nicely divided between more processors). First we will need function to test whether n is a prime: // Tests whether n is prime - expects n > 1
let is_prime n =
// calculate how large divisors should we test..
let max = int_of_float (Math.Sqrt( float_of_int n ))
// try to divide n by 2..max (stops when divisor is found)
not ({ 2 .. max } |> Seq.filter ( fun d -> n%d = 0) |> Seq.nonempty)
To find all primes in the specified range we could use the following code: let primes = [1000000 .. 1100000] |> List.filter is_prime
This code subsequently executes the is_prime function for all numbers that we want to test, but with multiple CPU cores it would be nice if the function divided the numbers into several parts and executed every part on different thread, so application would take benefit from multiple cores available in the system. The is_prime function doesn't have any side-effects so executing it several times in parallel can't change the result of operation (if the order of primes in the returned list doesn't change).
I wrote a function that does exactly what I described in the previous paragraph. To execute the operation in parallel, you can use the following code (the only difference is that I replaced List module with my ParallelList module): let primes = [1000000 .. 1100000] |> ParallelList.filter is_prime
On my notebook (with Intel Core Duo processor) the first code (using List.filter) takes about 2,3sec and using ParallelList.filter the operation takes only 1.3sec. The program isn't 2 times faster, because there is some overhead for creating and synchronizing threads, but in this case the speed increase is significant.
Aside from the filter function, the ParallelList module contains also the map function (which does the same thing as the List.map). There is also a function set_thread_count that you can use to configure how many threads should be used when executing parallel operations (the default value is 2).
Performance and future work
The performance of these functions is the key issue. Currently the ParallelList functions work can't be used for small number of repetitions of simple function, because the overhead is larger than the profit from parallel execution. If the operation takes less than 0.01ms and the number of repetitions is less than 1000 the List functions are usually better, but for operations taking longer time the results of ParallelList are better even with smaller number of repetitions. For operation taking about 0.1ms the ParallelList gives better results for more than 200 repetitions and for operation taking more than 1ms the number of repetitions is not very important (ParallelList is better even for 10 repetitions). These are inaccurate results that I got on my notebook, so if you're thinking of using the ParallelList, be sure to do some tests in your scenario! You can see some tests that I did in the demo project in stats.fs source file.
As I said earlier, ParallelList supports only filter and map functions, so implementing more functions would be useful. It would be also useful to provide some alternatives for functions that can't be executed in parallel (like fold_left) that could be used in some situations. I'd also like to implement functions for working with other collection types like Seq (IEnumerable) and array in the future.
I'm interested in your ideas and suggestions, so if you find something that could be improved in the code, or if you have any other idea, let me know!
Downloads
|
-
On 2nd of November I did a presentation on F# and functional programming at the Czech .NET User Group meeting.
Because I spent quite a lot of time with puting the presentation together I wanted to make it available to wider
audience, so I translated the slides and examples to English (anyway, translating the content took me only a few minutes :-)).
In case that some of the readers prefer Czech version, I attached the original documents too.
In the presentation I tried to introduce some basic concepts of functional programming (immutable values,
lazy evaluation) to the audience with no experience with functional programming, as well as present some
of the most interesting features of F# (like strict type system based on type inference, .NET interoperability and
metaprogramming). The whole contents of the presentation is following:
- Functional programming in F# - Introduction to the F# type system
- Some useful functional idioms - How to do Foldl/Map/Filter functions and Lazy evaluation in C#
- Interactive scripting - What is important for scripting, mathematical simulation
- Interoperability between F# and other .NET languages - How to use .NET libraries from F# and F# libraries from ohter .NET languages
- F# as a language for ASP.NET - How to use F# as a language for ASP.NET development
- Meta-programming in F# - Meta-programming features in F# and the FLINQ project
Downloads
|
-
Introduction
F# quotations allows you to easily write programs that manipulate with data representation
of program source code. If you're not familiar with quotations I recommend reading my
previous article [1] that contains short introduction
to this topic first. Quotations can be used for example for translating subset of the F# language to
another code representation or another language.
To get the quotation data of the expression you can either use <@ .. @>
operator or resolveTopDef function. In the first case the code written
between the "<@" and "@>" is converted to data during the compilation.
The resolveTopDef function allows you to get quotation data of top-level
definition (function) from compiled library at runtime (you have to use --quotation-data
command line switch while compiling the library). I mentioned that quotations can be used to represent
only subset of the F# language. Currently, one of the quotation limitations is that it's not possible to
enclose the whole class in the quotation operators. It is also not possible to get the representation
of the whole class at runtime nor the representation of class members (for example methods).
Class quotations
In one my project I wanted to be able to translate the class written in F# to another language,
so I wanted to make this possible. This option will be probably implemented in the future versions
of F#, so it will be possible to do this using more elegant method, but if you want to experiment
with quotations and use classes, you can use my solution to implement the prototype.
In the prototype I implemented, you have to write the class and one module that contains
the actual code for the methods. This makes it possible to get the structure of the class using
standard .NET reflection classes and to extract quotation data for the class members using
F# resolveTopDef function. Of course, you can't create instance of module, but for metaprogramming
we only need to be able to get the quoted code and unless you want to use the class from code, you can leave
the implementation of the class methods empty.
First I had to design the data structures for representing the class. If I were adding this feature to the F#
metaprogramming, I would probably extended the expr data type to make this possible in
consistent way. However I didn't want to modify the F# source code, so I designed the following types
that are similar to the expr type (I reversed the order of type declarations, so it
is easier to understand):
/// Structure that contains information about class -
/// consists of name, name of base class and members
type classInfo = {
name:string;
baseName:string option;
members:classMember list;
};;
/// Member of the class
/// For working with this type use cmfCtor, cmfMethod, cmfField, cmfProp..
type classMember;;
/// Type for working with class members
/// Query function tests whether member is of specified type
/// Make function creates member
type 'a classMemberFamily with
member Query : classMember -> 'a option
member Make : 'a -> classMember
end;;
/// Constructor declaration
/// - parameter should be lambda expression
val cmfCtor : (expr) classMemberFamily;;
/// Method delcaration
/// - method name, expression (should be lambda) and return type
/// (types of parameters are stored in lambda expression)
val cmfMethod : (string*expr*Type option) classMemberFamily;;
/// Field declaration
/// - field name, type and init expression
val cmfField : (string*Type*expr option) classMemberFamily;;
/// Property declaration
/// - property name, getter and setter (both should be lambda expr) and type
val cmfProp : (string*expr*expr*Type) classMemberFamily;;
This representation is still very limited - for example it isn't possible to represent
polymorphic methods. In the previous code, the classMember can be used to
represent any member (similarly to the F# expr that can represent any expression).
The cmf[Something] values are equivalent to the
ef[Something] from F# quotation library and allows you to work with
classMember type.
The following example shows how to write simple class with module that can be used for extracting
the quotation data:
#light
// Module with implementation of methods
module Person_Meta = begin
// Simulates field of the class
let name = ref ""
// Represents constructor
let ctor (n) =
name := n
// Represents method
let Say (pre:string) =
let s = pre^", my name is "^(!name)^"." in
print_string s
// Represents property
let get_Name () =
(!name)
let set_Name (value) =
name:=value
end
// The real class
// Members are just a placeholders and the quotations
// are extracted from the previous module
type Person = class
val mutable name : string;
new((n:string)) = { name = ""; }
member this.Say(pre:string) = ()
member this.Name with get() = "" and set((v:string)) = ()
end
In the last code sample, I'll show how the functions I wrote can be used for working
with the previous piece of code. To get the representation that I mentioned earlier of
the class Person, you can use function getClassFromType. This function
extracts structure of the class (from the class itself) and quoted code from the module
with the _Meta suffix. The following example is quite simple. It prints
basic class information (name and base name) and then iterates through all the members and
prints all available information for every member. For printing the expr type
(which represents the quoted code) I used printf function with the output_any formatter.
#light
do
// Get the class info for class 'Person'
let clsInfo = getClassFromType ((typeof() : Person typ).result)
// Print name and optional base name
Console.WriteLine("Class '{0}':", clsInfo.name)
if (clsInfo.baseName <> None) then
Console.WriteLine(" base: {0}", clsInfo.baseName)
// Iterate through class members
clsInfo.members |> List.iter ( fun m ->
match cmfMethod.Query m with
| Some (name, expr, ret) ->
Method "printf ( %s : %a ) = " name output_any ret
| _ ->
match cmfField.Query m with
| Some (name, typ, init) ->
printf "Field ( %s : %a) " name output_any typ
| _ ->
match cmfProp.Query m with
| Some (name, getter, setter, typ) ->
printf "Property ( %s : %a )\n" name output_any typ
printf "get = %a\n" output_any getter
printf "set = %a\n\n" output_any setter
| _ ->
match cmfCtor.Query m with
| Some (expr) ->
printf "Ctor = %a\n\n" output_any expr
| _ ->
failwith "Error!"
)
Conclusion
The aim of this article isn't to present fully working solution, but to suggest a few enhancements
to the F# metaprogramming that I think would be useful. You can use the source code attached to this
article to find (and experiment with) some interesting use cases of metaprogramming that require working
with classes, for example translating classes written in F# to another language. The biggest limitation
of the solution I presented is, that you have to write every implementation twice - it occurs in the
body of the class and in the module used for metaprogramming too (however the code looks very similar).
If you want to translate F# code, you don't need to implement methods/properties of the real class, but
if the program creates instances of the class at runtime (and uses the quoted code to perform some analysis etc.),
you'll need to write both implementations.
Downloads
Links and references
|
-
Some time ago, I wrote an article about useful utility called F# quotations visualizer. This utility can be used to show visual representation of F# quotations, which can represent (subset of) source code written in F#. There are two ways that you can use to get F# quotations - first is using operators <@@ ... @@> (this returns quotation of the code written inside the operator), second method is to get quotation of top level definition from compiled F# assembly (you have to explicitly enable this using command line switch --quotation-data while compiling assembly).
Because I added several new features to the original Quotations visualizer, I decided to publish the latest version - here is the list of main improvements:
- Application is rewritten using active patterns (new F# language feature)
- It is possible to extract quotations from compiled F# assembly (if it contains quotation data)
- Added support for several missing language constructs
Active patterns
Active patterns is a new (experimental) feature in the F# language. You can find some information about this feature in Don Syme's article [1]. In simple words, active patterns allows you to write "switch" consisting of functions (patterns) that return 'a option type. When the code is executed, it finds first pattern whose query returned a value (Some(...)) and the body of selected pattern is executed.
This feature makes it very easy to work with F# quotations because all ef[Something] values that are used for querying quotations have the required signature (the Query function that returns 'a option type), so they can be used with the active patterns feature.
In the quotations visualizer, we need to match the expression (type expr) with all possible expression families (ef[Something]) and choose the first one that matches. To see how active patterns work, you can look at the following part of the function that does this. First, without active patterns: match efForLoop.Query(expr) with
| Some(nfrom,nto,body) ->
// Statement: for i=start to end do body; done;
// .. create tree node ..
| _ ->
match efWhileLoop.Query(cond,body) with
// Statement: while condition do body; done;
// .. create tree node ..
| _ ->
match efCond.Query(t,(cond,trbody,flbody)) with
// if (cond) then trbody; else flbody;
// .. create tree node ..
| _ ->
// unknown expression
And with active patterns the source looks like this: #light
let EFForLoop = efForLoop
let EFWhileLoop = efWhileLoop
let EFCond = efCond
match expr with
| EFForLoop(nfrom,nto,body) ->
// Statement: for i=start to end do body; done;
// .. create tree node ..
| EFWhileLoop(cond,body) ->
// Statement: while condition do body; done;
// .. create tree node ..
| EFCond(t,(cond,trbody,flbody)) ->
// if (cond) then trbody; else flbody;
// .. create tree node ..
| _ ->
// unknown expression
This is very simple example and there are many situations where active patterns are even more helpful. You may have also noticed that the code doesn't contain any semicolons. This is the result of another new feature called lightweight syntax (it is turned on by the #light directive) - if you turn it on the whitespace becomes significant and compiler can understand structure of the code using whitespace instead of semicolons, parentheses and begin/end keywords. This feature is described in the F# manual [2].
Extracting quotations from assembly
When you specify --enable-quotation-data switch to the F# compiler, it stores quotation of every top level definition (functions in modules) in the assembly. This quotation can be later retrieved using resolveTopDef function, however to use the function for loading top-level definitions from another assembly, you first have to load quotation data from the assembly. The following snippet shows how to do this. let asm = Assembly.LoadFile(name) in
asm.GetManifestResourceNames() |> Array.to_list
|> List.filter (fun rn ->
rn.StartsWith(pickledDefinitionsResourceNameBase))
|> List.iter (fun rn ->
explicitlyRegisterTopDefs asm rn (readToEnd (asm.GetManifestResourceStream(rn))))
This code first loads the assembly (using LoadFile method which accepts assembly file path). Than it gets all managed resources of the assembly and selects only those resources, whose name starts with pickledDefinitionsResourceNameBase (this is a constant declared in Microsoft.FSharp.Quotations.Raw module). Now we have all resources containing F# quotation data, and we can use explicitlyRegisterTopDefs function to load quoted top level definitions. The explicitlyRegisterTopDefs method takes three parameters - assembly, name of the resource and resource data (byte array). When the top level definitions are registered using this method, it is possible to load quotations of functions declared in loaded assembly - and this is exactly what happens when you click on the "Open F# assembly" link in the application. If you are interested in the complete code, look at the attached source code of quotations visualizer application.
Links
Downloads
|
-
You probably already saw my post regarding CodeDOM generator for the F# language and how to use it with ASP.NET. To make it more accessible for everyone, I created project at the new Microsoft community site called CodePlex [^].
BTW: CodePlex looks like a really good site. It is based on Visual Studio Team System (which means that developers of the project can do most of the work directly from Visual Studio). It provides management of "Work Items" (TODO list), source control and many other useful things! For example if you have any feature requests or bug requests, send them to the discussion and I can easilly create work item from the message in the discussions.
If you are interested in this project and you want to help with developing of some parts, or if you are working on a project that is related to CodeDOM and F#, please let me know. Any help or feedback is kindly welcome!
|
-
CodeDOM and providers
CodeDOM (Code Document Object Model) is set of objects (located in System.CodeDom namespace) that can be used for representing logical structure of .NET source code. For example you can use CodeTypeDeclaration class to represent class declaration or CodeAssignStatement to represent assignment in the body of method. CodeDom is language independent and CodeDOM structure can be translated to source code in specified language using code generator (class that implements ICodeGenerator namespace). The CodeDOM structure can be also compiled to assembly using code compiler (implementation of ICodeCompiler interface). Microsoft provides several code providers with .NET Framework (for C#, VB.Net, JScript and C++), but you can add your own by by implementing previously mentioned interfaces.
In the .NET Framework, CodeDOM is used for automatic code generation. For example when you add web reference to your project, the wrapper class that calls web service is generated using CodeDom. Some more examples are typed dataset (generated from XSD files) and generator for data layer in the upcoming LINQ project, but the most interesting use for CodeDOM for me is in ASP.NET 2.0.
Typical ASP.NET web page consists of several aspx/ascx files and associated code behind files written in one of the .NET languages. When building web page, ASP.NET uses CodeDOM for building aspx/ascx files. It parses these files and generates according CodeDOM structure. For example <asp:Button id="btn" runat="server" /> declaration is translated to declaration of btn member and code that assigns new instance of Button object to this member. This generated structure is compiled to .NET assemblies using code compiler and the web page is ready to use. If you use any in-line code in ASP.NET page, it is included in the CodeDOM structure as literal, which means that if the generated CodeDOM is compiled using C# code compiler, it can contain literals only in C# language (because you can't mix languages in one source file).
ASP.NET and F#
In ASP.NET 1.1 you could compile code behind files using different compiler than the rest of the page (source generated from aspx/ascx). This method is used by ASP.NET in F# demo by Robert Pickering [1]. The more complex approach that is available in ASP.NET 2 is to write CodeDomProvider implementation for F#. This makes it possible to write F# in-line code in web pages and this method allows you to fully benefit of ASP.NET compilation model (for example you can use Publish Web Site command in Visual Studio).
FSharpCodeProvider & AspNetFsharpCodeProvider
I wanted to implement CodeDomProvider for the F# language, for the reasons mentioned above. Currently, I'm presenting version of provider that is able to compile ASP.NET pages quite well, however I implemented only features required by ASP.NET, so the provider is not complete. There are also some problems that has to be handled specially (for example, F# doesn't support partial classes), so apart from standard provider (FsharpCodeProvider), I also implemented AspNetFsharpCodeProvider that contains several 'hacks' for ASP.NET.
How to use it?
Important: For correct functionality of F# CodeDOM compiler, you have to modify your system variable PATH to include 'bin' directory of your F# installation folder. This is because, code compiler uses fsc.exe for compilation and there is no simple way for finding where the F# is installed.
The most simple way to start creating ASP.NET web sites in F# is to use VS.NET project template that you can find in the downloads section. Using this template, you can create web page that is already configured to use F# language. After installation, select File - New - WebSite.. and in the dialog select language 'Visual C#' (it is not possible to add another language AFAIK) and than select 'F# WebSite' template.
If you want to configure ASP.NET web site to use F# code provider manually, you have to do the following steps. First modify the web.config file to include the following elements in the compilation section: <?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true">
<compilers>
<compiler language="F#;f#;fs;fsharp" extension=".fs"
type="EeekSoft.FSharp.CodeDom.AspNetFSharpCodeProvider, fscodeprovider"/>
</compilers>
</compilation>
</system.web>
</configuration>
This adds reference to the assembly that contains the AspNetFShaprCodeProvider class and it configures ASP.NET to use F# code generator for aspx files which Language attribute is set to "F#". When this is done, you can add F# page by adding aspx and code behind fs files. In the Page directive, set the Language attribute to "F#" and define the code behind class in the fs file.
The following example shows code behind class for simple web page (that contains one button with ID set to btnOk): namespace FSharpWeb
open System;;
open System.Web.UI.WebControls;;
// Code behind class declaration
type Default = class inherit System.Web.UI.Page as base
// Declaration of button control
val mutable btnOk : Button;
// All fields must be initialized in constructor
new() = { btnOk = null; }
// Set text of button in onload
override this.OnLoad (e) =
btnOk.Text <- "Hello world!";
base.OnLoad (e);
end;;
There is still one little difference when compared with C#, which is that it is required to manually declare all controls (with ID) that are on the page (btnOk in this example). This is because F# doesn't (currently) support partial classes and so the partial class with control declarations that is generated by ASP.NET is dropped by the CodeDOM provider. The rest is very similar to how you develop ASP.NET pages in other languages; you can see more examples if you download attached example application. More information regarding object oriented programming in F# can be found in F# manual available at F# homepage [3].
Other CodeDom provider notes
As I mentioned earlier, the CodeDOM generator I created is still very limited and it is tested only with ASP.NET. You can find list of not implemented features in the release notes (see downloads). In the future, I'd like to extend it to support generating code for accessing web services too (code is generated using wsdl tool). If you have any interesting idea, how it could be used or if you have any other comments, ideas, bug fixes, etc., please let me know (at tomas@tomasp.net).
Downloads & links
|
-
This article describes very simple code that I wrote while learning how to work with the F# quotations library. Using the F# quotations you can get tree representation of the quoted expression. This allows you to write code that takes code written in F# as data and performs some code analysis or compiles/translates that code to different language. This is very similar to the new C# 3.0 expression trees where you can get expression tree from lambda expression and translate this tree for example to SQL (using DLINQ). However expression trees in C# 3.0 are very limited when compared with F# quotations, so that's one of the many reasons why F# is interesting language.
Introduction to F# quotations
If you want to see how F# represents some expressions you can try it in the FSI (F# interactive). First you need to open three modules that contain functions for working with quotations: open Microsoft.FSharp.Quotations;;
open Microsoft.FSharp.Quotations.Raw;;
open Microsoft.FSharp.Quotations.Typed;;
Now you can see the internal representation of quotations by writing quoted expression (In VS.Net you can select code and hit Alt+Enter to sent selected code to F# interactive). <@ 1 + 2 @>
val it : int expr
= <@
Microsoft.FSharp.MLLib.Pervasives.op_Addition (Int32 1) (Int32 2)
@>
One more example with two operators: <@ 1 + 10/5 @>
val it : int expr
= <@
Microsoft.FSharp.MLLib.Pervasives.op_Addition (Int32 1)
(Microsoft.FSharp.MLLib.Pervasives.op_Division (Int32 10) (Int32 5))
@>
It is not difficult to understand that addition in the first example is represented as function call (function application in the terminology of functional languages) where the function is op_Addition operator and parameters are two integers. This is actually little simplification, because in functional programming you should look at this code as two function applications. The first application binds first parameter of op_Addition to 1 and the result is again function. The second application uses the function returned by the first application and passes 2 as parameter. You can look at F# quotations using both approaches and in the rest of the article I will use the first one.
To demonstrate how to work with F# quotations I decided to write simple transformation of limited mathematical expressions from F# quotations to my data type. The discriminated union that I'm using as target of transformation is similar to the union in F# source file VS.Net template (as you can see it supports only four most basic mathematical operations and all values are stored as integers): type simple_expr =
| Int of int
| Add of simple_expr * simple_expr
| Sub of simple_expr * simple_expr
| Mul of simple_expr * simple_expr
| Div of simple_expr * simple_expr;;
Printing and evaluation of this structure is simple, so I won't describe these here. If you want to look at these functions see attached source code. (function for evaluation is part of VS.Net template too).
Working with quotations
Finally, let's do the interesting part :-). As I mentioned you can get quotations using <@ ... @>. When you want to perform analysis of quotations you need to get the underlying raw representation using the <@@ ... @@> operators. For decomposing the quoted expression we can use Query functions on the expression families defined in the Raw module. This may sound a bit confusing, but in the simple words - the Raw module contains several values that define language constructs (like constants, variables, function application and others) and you can use these values for matching and decomposing quoted expression. Following code should clear this a bit: let what_is x =
match Raw.efInt32.Query x with
| Some (_) -> "number";
| _ ->
match Raw.efApps.Query x with
| Some (_) -> "application";
| _ ->
"something else...";
// Prints "number"
print_string (what_is <@@ 1 @@>);
// Prints "application"
print_string (what_is <@@ 1 + 2 @@>);
Now we can start writing function that converts mathematical expression quotation to simple_expr structure. It will be recursive function with similar structure as previous. The first match for conversion of numbers will be simple. In the second match we'll have to do two things. First we'll need to determine what function is applied (whether it is addition, subtraction, etc..) and than we'll have to loop through parameters passed to this function and call the function recursively each parameter. let rec parse x =
match Raw.efInt32.Query x with
// x contains the number so we can simply return Int(x)
| Some (x) -> Int(x);
| _ ->
match Raw.efApps.Query x with
| Some (op,args) ->
// op contains quoted reference to function (operator)
// so we need to extract name of applied function from it
let opname = (
match Raw.efAnyTopDefn.Query op with
// operators are top-level definitions so we extract name
// from 'a' that contains info about the definition
| Some (a,_) -> let t1,t2 = a.topDefPath in t2
| _ -> failwith ("Function is not a top level definition.");
) in
// Recursively translate arguments to simple_expr
// and convert returned list to array
let av = List.to_array(List.map (fun arg -> parse arg) args) in
// Finally, match the operation name with basic
// operator names and return according simple_expr value
(match opname with
| "op_Addition" -> Add(av.(0),av.(1))
| "op_Subtraction" -> Sub(av.(0),av.(1))
| "op_Multiply" -> Mul(av.(0),av.(1))
| "op_Division" -> Div(av.(0),av.(1))
| _ ->
// some other operation - error
failwith "Not supported operation");
| _ ->
// something else than efApps and efInt32 - error
failwith "Not supported construction in expression.";;
As I mentioned, the more interesting part of the code is when the quotation matches with efApps which in our case means that the expression is mathematical operation. From the functional point of view efApps means series of function applications. The result of Query function of efApps is tuple containing expression with information about applied function (operator in our case) and parameters of this application.
For extracting operator name we match the first value with efAnyTopDef which returns information about top-level definitions. Returned structure contains assembly name as well as the function name that we need. In the second step we recursively call parse function to all arguments of operator. Once we know the function name and we have arguments translated to simple_expr, we can return the according simple_expr value.
(Cross-posted from: http://tomasp.net/blog/fsquotations.aspx)
|
-
So this is my first post to hubFS :-). First I'd like to give thanks to optionsScalper for creating blog for me. Before writing some more interesting posts on F# I'd like to introduce myself...
I'm student of computer science from Czech Republic (studying at Charles University of Prague). I'm also Microsoft C# MVP and I'm student consultant at our university. As student consultant I'm organizing presentations on several (mostly) Microsoft technologies and I'm also often talking there. Aside from studying I worked on many .NET projects including mostly ASP.NET development.
I started learning F# some time ago (but I'm still very far from knowing it well) and I was impressed with so many interesting possibilities of this language. So far, my favorite F# feature is meta-programming (also known as F# quotations), so my first posts will be focused on this topic.
My homepage is http://tomasp.net and most of the content that I publish somewhere else is also available at my homepage. You can contact me at tomas@tomasp.net
|
|
|