|
|
|
|
 Friday, May 07, 2010
|
In Visual Studio 2010, you can now get your F# unit tests loaded by the IDE. First, create your F# test project. This is just a normal library referencing Microsoft.VisualStudio.QualityTools.UnitTestFramework and having test classes and so on. The only change you need to do is go into the configuration and set the output folder to "bin" for both debug and release (instead of bin\debug).
Next, create a C# Test Project, and delete the code file. Then add an existing item, and navigate to the bin directory of your test project output. Select the DLL and Add as Link.
Finally, right click the solution, and change the project dependencies so the C# test project depends on your F# test project.
That's it. Now the IDE will pickup your F# tests and allow you to manage, run, and debug them right from VS. You may have to restart the IDE after setting all this up for it to work smoothly.
|
|
Code | FSharp
|
Friday, May 07, 2010 4:57:57 AM UTC
|
Trackback
|
 Wednesday, April 28, 2010
I've updated the code we use for FluentNHibernate with F# - using the final versions of both products. It's just some code to fixup F# quotations to LINQ expressions that FluentNHibernate can work with, and type extensions to make it easy to consume from F#.
The FluentNHibernate RTM zip has all the other binaries you need to get started.
I'm building against .NET 4, but the code should work on 2.0 as well.
FluentNHibernate.FSharp.dll (38.5 KB)
FluentNHibernate.FSharp.zip (6.95 KB) Source
And here's the FluentNHibernate sample first project using FluentNHibernate.FSharp:
FirstProject.zip (7.66 KB)
Here's an example of what some mapping code looks like:
type
ProductMap() as m = inherit
ClassMapQ<Product>() do
let
x = m.DefaultX
m.Not.LazyLoad()
(m.IdQ <@ x.Id
@>).Done
(m.MapQ <@ x.Name
@>).Done
(m.MapQ <@ x.Price
@>).Done
(m.HasManyToManyQ <@ seq
x.StoresStockedIn @>)
.LazyLoad()
.Cascade.All()
.Inverse()
.Table("StoreProduct")
.Done
|
|
Code | FSharp
|
Wednesday, April 28, 2010 9:56:22 PM UTC
|
Trackback
|
 Thursday, July 16, 2009
|
I came across a thread on hubFS about deserialising F# records with JSON. After Mr. McNamara pointed out that DataContract serialization would work with F# records, I realised we can do the same for other serialisation systems, such as ASP.NET MVC.
ASP.NET MVC binding doesn't work with F# records for a few reasons. First, it requires a default constructor, and record types don't have one. Second, it needs settable properties, and records have read-only properties. Fortunately, the backing field for a record's property is a mutable field. The name is mangled (@ is appended), but otherwise we're ok to set that field.
With this, we can subclass the default model binder and add in code to construct records as well as set their fields directly. Unlike DataContract serializers, I didn't use FormatterServices.GetUninitializedObject to create the object, I use the F# reflection function MakeRecord. This is because I want to attempt to initialise all fields on the record type, to try to keep out nulls. This goes against how the rest of MVC's null handling goes, so perhaps it's not a great idea.
At any rate, here's the quite short code. A lot of things probably don't work, such as F# lists. Perhaps there should be a community project that collects F#-specific type helpers for different frameworks to make serialization, binding, etc. easier.
open System
open System.Web.Mvc
open Microsoft.FSharp.Reflection
type RecordDefaultModelBinder() =
inherit DefaultModelBinder()
let isrec = FSharpType.IsRecord
/// Makes a record, trying to provide initialised values for each field
let rec makeDefaultRecord ty =
let defval ty =
if isrec ty then makeDefaultRecord ty
else match ty.GetConstructor(Type.EmptyTypes) with null -> null | c -> c.Invoke null
let vals = FSharpType.GetRecordFields ty |> Array.map (fun x -> defval x.PropertyType)
FSharpValue.MakeRecord(ty, vals)
override this.CreateModel(cc, bc, ty) =
// We have to avoid them calling Activator.CreateInstance on records
if isrec ty then makeDefaultRecord(ty) else base.CreateModel(cc, bc, ty)
override this.GetModelProperties(cc, bc) =
// Default one filters out read-only, but we own the field
if isrec bc.ModelType then
let props = ComponentModel.TypeDescriptor.GetProperties(bc.ModelType)
|> Seq.cast<ComponentModel.PropertyDescriptor> // BCLFail
|> Seq.filter(fun p -> bc.PropertyFilter.Invoke(p.Name))
ComponentModel.PropertyDescriptorCollection(Seq.to_array props)
else
base.GetModelProperties(cc, bc)
override this.SetProperty(cc, bc, propDesc, value) =
// To set a record property, set the mangled field
if isrec bc.ModelType then
let field = bc.ModelType.GetField(propDesc.Name + "@", Reflection.BindingFlags.Instance ||| Reflection.BindingFlags.NonPublic)
field.SetValue(bc.Model, value)
else
base.SetProperty(cc, bc, propDesc, value)
|
|
ASP.NET | FSharp
|
Thursday, July 16, 2009 9:35:53 AM UTC
|
Trackback
|
 Friday, May 15, 2009
|
If you use ASP.NET MVC with F# CTP (Monday brings Beta 1 and probably many changes), you might run into an issue of how to scope certain things. For example, an IDisposable is used to create blocks, for things like an HTML form. Example in C#:
<% using (Html.BeginForm()) {%>
<fieldset><legend>Fields</legend>...</fieldset>
<% } %>
This is needed because VB and C# didn't have any easy function/block syntax (VB 10 should fix this), and many C# developers are still wary of higher order functions. How does this play out in F#? First off, whitespace is important. This can get really messy with the current F# ASP.NET integration. Basically, always open the script blocks on a separate line, and indent from the first column. Example:
<% let i = 0
this.Response.Write(sprintf "i = %d" i) %>
(Note that the 'this' variable is bound to the current page.) This fails:
Compiler Error Message: FS0010: Unexpected keyword 'let' or 'use' in expression. Expected incomplete structured construct at or before this point or other token
Source Error:
|
Line 111: let mutable parameterContainer = parameterContainer
Line 112: __w.Write("\r\n") |> ignore
Line 113: let i = 0
Line 114: this.Response.Write(sprintf "i = %d" i)
Line 115: __w.Write("\r\n <h2>Create</h2>\r\n\r\n ") |> ignore |
Note how the <% is counted as space, so the let starts off indented 3 spaces. Instead, we need to write it so:
<%
let i = 0
this.Response.Write(sprintf "i = %d" i) %>
This works fine. You can also put the %> on the next line if you like. Now, on to ASP.NET MVC's IDisposable usage. A straightforward use of the F# using function won't work:
<b>Demo</b>
<%
using (Mvc.Html.FormExtensions.BeginForm this.Html) (fun _ -> %>
<p>Inside a form</p>
<% ) %>
Compiler Error Message: FS0191: The mutable variable '__w' is used in an invalid way. Mutable variables may not be captured by closures. Consider eliminating this use of mutation or using a heap-allocated mutable reference cell via 'ref' and '!'.
Source Error:
|
Line 114: __w.Write("\r\n\r\n<b>Demo</b>\r\n\r\n") |> ignore
Line 115:
Line 116: using (Mvc.Html.FormExtensions.BeginForm this.Html) (fun _ ->
Line 117: __w.Write("\r\n\r\n <p>Inside a form</p>\r\n\r\n") |> ignore
Line 118: ) |
As the error says, this is because the __w variable is mutable, so we can't play with it inside a lambda. I'm not sure if this will be worked around -- they'd have to change the codegen quite a bit, I'd think. As a side note, the F# CTP does not support C# extension methods (hence the verbose calling of BeginForm), but F# will eventually -- maybe in the Beta.
The way we must scope is with a use binding. There's no way I see to accomplish this with whitespace alone. Due to the ASPX translation process, this would probably be very error prone. Instead, we can simply put the use binding inside a do expression:
<b>Demo</b>
<%
do (use form = Mvc.Html.FormExtensions.BeginForm this.Html %>
<b>Inside the form</b>
<% ) %>
<b>Outside of the form</b>
The parentheses setup the scope exactly how we want it.
|
|
ASP.NET | FSharp
|
Friday, May 15, 2009 8:46:39 PM UTC
|
Trackback
|
 Thursday, April 23, 2009
|
Last time, I hacked up some rudimentary support for F# and Fluent NHibernate. It really looked ugly. I looked into what I could do to make it not look as sucky.
First off, having to write a full lambda for each mapping was annoying. F# quotations don't have to be lambdas, unlike C#'s expressions. So, instead of having to write, say, "fun x -> x.Foo", we can write "x.Foo", assuming there's a local variable x with the right type. The ClassMap subclass now expects these types of quotations than full lambdas.
Next, I experimented with using type extensions to overload functions like Id and Map, however I found out that F#, at least currently, does not add in type extensions for overload resolution. So I ended up having a new subclass of ClassMap<T>, 'T ClassMapQ. I used the Q suffix consistently to denote "quotations". I added type extensions for most of the other mapping types so that quotations could be used.
As to the question of having to tag on " |> ignore " to each mapping, I decided to write an extension propery for IMappingPart called Done, which is simply unit. Finally, the problem of lazy loading I took care of by setting "use_proxy_validator" to false, as mentioned here. The end result is that this mapping code:
type StoreMap() = inherit ClassMap<Store>() do
base.Not.LazyLoad()
base.Id ~@@ <@ fun x -> x.Id @> |> ignore
base.Map ~@@ <@ fun x -> x.Name @> |> ignore
(base.HasManyX <@ fun x -> upcast x.Staff @>)
.LazyLoad()
.Inverse().Cascade.All() |> ignore
(base.HasManyToManyX <@ fun x -> upcast x.Products @>)
.Cascade.All()
.WithTableName("StoreProduct") |> ignore
Is now:
type StoreMap() as m = inherit ClassMapQ<Store>() do let x = m.DefaultX (m.IdQ <@ x.Id @>).Done (m.MapQ <@ x.Name @>).Done (m.HasManyQ <@ seq x.Staff @>) .LazyLoad() .Inverse().Cascade.All() .Done (m.HasManyToManyQ <@ seq x.Products @>) .LazyLoad() .Cascade.All() .WithTableName("StoreProduct") .Done
This is pretty enough that I'm satisfied with how well F# interops. Most of the things I figured out here will apply to other .NET OO APIs, not just this one.
I am hoping that VS2010 Beta 1 will ship soon, as F# is getting some interesting upgrades then. With that, it should be easier to extend the support to other parts of NHibernate, such as querying, and perhaps integrate in NHibernate.Linq.
|
|
FSharp
|
Thursday, April 23, 2009 7:06:45 PM UTC
|
Trackback
|
 Wednesday, April 01, 2009
|
Fluent NHibernate is a nice way to be able to use NHibernate without having to deal with all that unchecked XML. This morning I decided to find out how well it works with F#. Things went relatively smooth. I've converted some code samples from the Fluent NHibernate First Project. I suggest having that open to fill in any gaps. I've also included the full project code and DB script at the end of this article.
If you're not familiar at all with Fluent NHibernate, basically it takes advantage of lambda expressions as Expression<T> to provide a somewhat strongly typechecked reflection system. Thus, instead of having attributes with hard-coded strings, or XML files, you have expressions that target the properties of objects you wish to map. The Fluent NHibernate library then takes care of hooking it up to NHibernate, and away you go. Something like that anyways.
Classes
So, first, we define the "entities" like the C# project does. Here's the first little pain. F# doesn't really support C#'s idea of "automatic properties". You can have vals on a class, which act like fields (although, they are implemented as properties). Or, you can manually specify them, like you would in earlier versions of C# which didn't have the auto-gen-a-field-for-me.
F# doesn't encourage uninitialized values. If you have uninitialized fields (vals), you need to mark them with an attribute to say you know what you're doing. So, that adds a bit more code overhead. What I do here is to alias the DefaultValueAttribute to "DV". So the first bit of our classes looks like this:
#light
namespace FHib.Entities
open System.Collections.Generic
type DV = DefaultValueAttribute
type Employee() as this =
[<DV>] val mutable Id : int
[<DV>] val mutable FirstName : string
[<DV>] val mutable LastName : string
Now, NHibernate relies on having virtual properties so that it can dynamically create code to do nifty things like lazy loading. In F#, creating a virtual member means defining an abstract member and providing an implementation, in the same class. Since we don't have automatic properties, this means we'll have to define the backing field ourselfs. In all, the full code for the virtual property "Store" (virtual so NHibernate can lazy-load it) is:
abstract Store : Store with get,set
[<DV(false)>] val mutable _store : Store
override x.Store with get() = x._store and set(v) = x._store <- v
Not the pinnacle of short code, but not horrible all things considered. The rest of the entity mappings are rather straightforward so I'll skip them here. I stuck with vals for anything that didn't have to be virtual, to keep it more concise.
Mappings: Easy Start
OK, so now to the "real" work. Fluent NHiberate looks for classes that subclass ClassMap<T>. It then creates an instance of them, which allows you to call the mapping methods in the object's constructor. From the First Project: public class EmployeeMap : ClassMap<Employee> {
public EmployeeMap() {
Id(x => x.Id);
}
}
OK, so how do we convert this to F#? It's easy... except for that lambda. The lambda in this case compiles to an Expression<Func<Employee, object>>. F#'s compiler does not support Expression<T>. So, we turn to experimental support. Referencing the FSharp.PowerPack.Linq assembly gives us the Microsoft.FSharp.Linq.QuotationEvaluation module. This extends the F# quotation type, Expr, with "ToLinqExpression", which returns an untyped LINQ Expression object.
To get this untyped Expression (LINQ) out of an Expr (F#) and into an Expression<T> (F#) suitable for Fluent NHibernate's consumption, I started off writing this tiny helper module:
module LinqHelper =
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation
open System.Linq.Expressions
let ToLinq (exp : Expr<'a -> 'b>) =
let linq = exp.ToLinqExpression()
let call = linq :?> MethodCallExpression
let lambda = call.Arguments.[0] :?> LambdaExpression
Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters)
When an F# quotation of a lambda is turned into a LINQ expression, the root node is a useless MethodCallExpression. So, we unwrap that by taking it's argument and using it to generate a typed lambda Expression<T>.
This is a good start. But many of the Expressions that Fluent NHibernate looks for have a return type of object. Instead of having to write "box" or "upcast" all over, I added another function called "ToLinqObj". This takes an Expr<'a -> 'b>, but returns an Expression<Func<'a, obj>>.
Finally, writing "ToLinq" and "ToLinqObj" seemed too verbose, so I added some operators to the LinqHelper module:
let (~@) expr = ToLinq expr
let (~@@) expr = ToLinqObj expr
Now we can start mapping:
open LinqHelper
type EmployeeMap() = inherit ClassMap<Employee>() do
base.Not.LazyLoad()
base.Id ~@@ <@ fun x -> x.Id @> |> ignore
base.Map ~@@ <@ fun x -> x.FirstName @> |> ignore
base.Map ~@@ <@ fun x -> x.LastName @> |> ignore
(base.References ~@ <@ fun x -> x.Store @>).LazyLoad() |> ignore
We start off by disabling LazyLoad because most of the properties are not virtual, and NHibernate will fail to validate the mapping. Instead, we explicitly LazyLoad things, like the Store reference.
Mappings: Modifying the Expressions
Unfortunately, things didn't stay so simple. The Fluent NHibernate methods "HasMany" and "HasManyToMany", for instance, don't work with F#'s type inference. This is because they have several overloads, a couple of which take expressions. If we try this in the StoreMap:
base.HasMany ~@@ <@ fun x -> x.Staff @> |> ignore
We get an error because F# doesn't know what x is. (error FS0055: This lookup uses a deprecated feature, where a class type is inferred from the use of a class field label. Consider using a type annotation to make it clear which class the field comes from.) Using ~@ to keep it strongly typed fails as well; it can't figure out the overload. This is nothing surprising -- overloading is the enemy of type inference.
So, what do we do? Type annotations are not what I consider fun. So instead, we'll add non-overloaded ClassMap<'t> type extensions into the LinqHelper module:
type ClassMap<'t> with
member x.HasManyX expr = (x.HasMany : Expression<Func<'t, seq<_>>> -> _) (ToLinq expr)
member x.HasManyToManyX expr = (x.HasManyToMany : Expression<Func<'t, seq<_>>> -> _) (ToLinq expr)
By providing these extensions that are explicit once, we enable type inference for the rest of the time. We can now finish the StoreMap:
type StoreMap() = inherit ClassMap<Store>() do
base.Not.LazyLoad()
base.Id ~@@ <@ fun x -> x.Id @> |> ignore
base.Map ~@@ <@ fun x -> x.Name @> |> ignore
(base.HasManyX <@ fun x -> upcast x.Staff @>)
.LazyLoad()
.Inverse().Cascade.All() |> ignore
(base.HasManyToManyX <@ fun x -> upcast x.Products @>)
.Cascade.All()
.WithTableName("StoreProduct") |> ignore
The only type "annotation" we need here is the upcast for the HasManyX. This is because F# forces you to be explicit. Accessing "Staff" in the first quotation means type IList<Employee>, not seq<Employee>. The upcast will sort this out for us.
This compiles fine. But remember how I said using expressions was a "somewhat strongly typed" way of doing things? The expression trees are interpreted at runtime, which allows failures a more complex type system might prevent. This is one of the times. If we try to execute it as-is, we get this exception:
---> FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException: Not a member access Parameter name: member
Ouch. Fluent NHibernate does not appreciate our expression trees. Why? Using FSI, we can inspect what we're actually converting the F# quotations to:
type SomeClass() = member x.Stuff = [|1;2;3|];; let myExpr : Expr<SomeClass -> seq<int>> = <@ fun x -> upcast x.Stuff @>;; let myLinq = LinqHelper.ToLinq myExpr;;
> myLinq;; val it : Linq.Expressions.Expression<Func<SomeClass,seq<int>>> = x => (x.Stuff As IEnumerable`1) {Body = (x.Stuff As IEnumerable`1); NodeType = Lambda; Parameters = seq [x]; Type = System.Func`2[FSI_0022+SomeClass,System.Collections.Generic.IEnumerable`1[System.Int32]];}
> myLinq.Body;; val it : Linq.Expressions.Expression = (x.Stuff As IEnumerable`1) {IsLifted = false; IsLiftedToNull = false; Method = null; NodeType = TypeAs; Operand = x.Stuff; Type = System.Collections.Generic.IEnumerable`1[System.Int32];}
So, what's going on? The upcast is modifying the F# quotation (as it should), and the ToLinqExpression is sticking this in as a "TypeAs" node. Fluent NHibernate does not seem to like this. Not. One. Bit.
But, it IS ok if we have a Convert node in the Expression tree. I imagine this is because C# generates such nodes in its expression trees (say, accessing an int member in a Func<T, object> expression). So, our last hack in making F# work right here is adding a fixup function to our LinqHelper, and using it from ToLinq:
let fixup (lexpr:LambdaExpression) =
if lexpr.Body.NodeType <> ExpressionType.TypeAs then lexpr else
let typeAs = lexpr.Body :?> UnaryExpression
let newBody = Expression.Convert(typeAs.Operand, typeAs.Type)
Expression.Lambda(lexpr.Type, newBody, lexpr.Parameters)
Now it's happy with our expressions.
Finally
The rest of the First Project is pretty straightforward in F#. For instance, creating the Session Factory:
let createSessionFactory() =
Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2005.ConnectionString(fun csb ->
csb.Is("server=(local);database=fhib;Integrated Security=true") |> ignore))
.Mappings(fun m ->
m.FluentMappings.AddFromAssemblyOf<Mappings.EmployeeMap>() |> ignore)
.BuildSessionFactory()
Everything seems to execute as it should. Fluent interfaces in F# generate a bit more noise, because of all the ignores that have to be added. I'm thinking of creating a type extension to obj to add Ignore as a method, to make it look a bit more uniform.
Future
It's my hope that F# has now addressed most of these issues -- 1.9.6 is 7 months old. Expression<T> is growing in importance, outside of LINQ querying, so I cannot see F# not being able to handle them easily and generating similar output to C#. It'd be really neat if F# would auto-convert quotations to Expression<T> when the expr is a syntactic argument like it does with delegates now. I'd also be surprised if abstract/virtual members still lack the ability to define accessibility.
Code: fhib.zip (4.76 KB) I did not include Fluent NHibernate or any of its dependencies. The project expects them to be in the project's lib folder, so get them here if you don't have them and extract them to "lib".
I welcome comments on this and suggestions for making the code more concise.
|
|
Code | FSharp
|
Wednesday, April 01, 2009 8:01:29 AM UTC
|
Trackback
|
 Tuesday, November 25, 2008
On a current project, I'm using F# with ASMX Web Services (Mono, so no WCF). I started off declaring some types like this:
type Account() = [<DefaultValue>] val mutable Name : string [<DefaultValue>] val mutable Data : byte array
We have to tag "default value" to tell F# it should go generate the default (Unchecked.defaultof<'a>) -- in this case, null.
Unfortunately, the serialized XML is not what we want. Currently F# generates both a public field ("_Name") and a get/set property ("Name") to access it. I'm not sure why this is, but there's probably some interesting reason (the part of the spec is 10.2.7 Explicit Fields, but it doesn't mention the implementation). The workaround is simple: tag the field with "XmlIgnore".
As of F# 1.9.3.7, you can choose to target an attribute at the property or the field for a val in a class type. See: http://blogs.msdn.com/dsyme/archive/2007/11/30/full-release-notes-for-f-1-9-3-7.aspx (I didn't find this part in the spec.)
So, the revised declaration for the XmlSerialization-friendly type is:
type Account() =
[<DefaultValue; field: XmlIgnore>]
val mutable Name : string
[<DefaultValue; field: XmlIgnore>]
val mutable Data : byte array
I found that to add a lot of noise, so I aliased them:
type DV = DefaultValueAttribute type XI = XmlIgnoreAttribute
type Account() =
[<DV; field: XI>] val mutable Name : string [<DV; field: XI>] val mutable Data : byte array
Now it works just fine and creates the XML we'd expect.
One other thing might bite you: null. F# rightfully eschews null. If you have a function that returns one of these types, you'll find it won't let you return null:
> let test() : Account = null;; let test() : Account = null;; -----------------------^^^^^ stdin(6,24): error FS0043: The type 'Account' does not have 'null' as a proper value.
This is generally good, but unfortunately, interop with the unenlightened world is sometimes necessary. The right way to do this is:
let test() : Account = Unchecked.defaultof<Account>;;
That's a bit too verbose for my liking, since I have to go annotate the type. A simple function will get around that:
> let inline getnull() = Unchecked.defaultof<_>;; val inline getnull : unit -> 'a
> let test() : Account = getnull();; val test : unit -> Account
Yes, I know it's not null, but default, but I think the purpose is clear enough.
|
|
FSharp
|
Tuesday, November 25, 2008 2:16:33 AM UTC
|
Trackback
|
 Monday, November 03, 2008
Several times I've had to explain a few basic F# things to new users. I ran into some of these too when I first looked at F#. If you've been looking at F#, but some things still don't click, I hope this will help break the chains of C/imperative languages. I'm assuming you know a bit about F#, perhaps from the Quick Tour or the F# Tutorial file that comes with the Visual Studio integration.
Functions always take and receive exactly one argument. Despite anything you see, in F#, there's only one argument, and only one return value. Let's look at how this plays out (I suggest firing up F# interactive and playing around):
> let inc x = x + 1;; val inc : int -> int
> let add x y = x + y;; val add : int -> int -> int
[I like to read -> as "to", because it's short and sweet.] So, for the case of "inc x", we see the signature is quite simple and expected "int to int". But for add? We see "int to int to int". What this actually means is "a function that takes an integer, and returns a function that takes an integer and returns an integer".
The same signature in C# would look like this: Func<int, <Func<int,int>>> or "Func<int,int> Add(int x)". [Some day, think how odd it is to have two ways of representing the function.] So when we call the F# function, we're really passing in the first argument, getting a new function, then applying the second argument. Something like this:
1. add x y 2. (add x) y 3. closure1 y 4. final-result
"closure1" is what we get from the "partial" application of add. I'll touch on this in a minute.
So how do we _really_ pass in two arguments at once? We put two arguments into one value, a tuple. We write it like this:
> let add (x, y) = x + y;; val add : int * int -> int
Notice the new type signature: "int by int to int" or "int int tuple to int". In C#, this would be:
int add(Tuple<int,int> arguments) { return Tuple.A + Tuple.B; }
But F# nicely provides support for tuples [via pattern matching], so we can write them much more naturally. This syntax also works on the way out:
> let pow23 x = x*x, x*x*x;; val pow23 : int -> int * int // "int to int int tuple"
> let square, cube = pow23 7;; val square : int val cube : int
> square, cube;; val it : int * int = (49, 343)
There's never no value Another common typo/misunderstanding is when creating a function with no arguments:
> let sayHi = printfn "Hi";; val sayHi : unit
Hi > sayHi;; val it : unit = ()
Oh, what happened here? Remember how _everything_ takes and returns exactly one value? The same is true of functions that "don't return a value", such as printf. Instead of "not returning a value" like C's void, functions return a special type called unit with one value, ().
Armed with this, let's see what the sayHi definition actually says. It says "let a value called sayHi equal to the result of printfn". Well, since the result of printfn is unit, sayHi becomes unit. The execution happens immediately, and subsequent uses of sayHi just get the value, unit.
To actually do what we want, we need to take an argument. Then F# knows we're a function value:
> let sayHi() = printfn "Hi";; val sayHi : unit -> unit
> sayHi;; val it : (unit -> unit) = <fun:clo@0>
> sayHi();;
Hi
val it : unit = ()
By explicitly taking a unit parameter, sayHi becomes a function (type unit to unit). Notice that if we just write "sayHi", we're just going to get the _value_ of it (a function), not apply (execute) the function.
Partial application OK, so a side effect of this system of "take on param and return a function that takes the next", is that we can compose with just parts of a function. For instance, to write an increment function, we can do this:
> let add x y = x + y;; val add : int -> int -> int
> let inc x = add x 1;; val inc : int -> int
So far, nothing interesting. However, we can also write this more effectively:
> let inc = add 1;; val inc : (int -> int)
Aha! What's happening here is what happens "secretly" each time we call add with 2 parameters. We're just using the intermediate result, the closure of "add 1", and assigning that function value to inc. In C#, it'd be something like this:
public static Func<int, int> Add(int x) {
return y => x + y;
}
public static Func<int, int> Inc = Add(1);
// and "full application" of add looks like this: Add(1)(2)
[BTW, this isn't really currying in F#. Currying is taking a method of type "a' * 'b -> 'c" and turning it into "'a -> 'b -> 'c". Since F# methods are "automatically curried", there's no need for a "curry" step (well, except perhaps when using .NET methods, which are always "tupled", but that's another story).]
[Side note: a function like "add" is superfluous, because in F#, operators are functions: > (+);; val it : (int -> int -> int) = <fun:clo@18> > let inc = (+) 1;; val inc : (int -> int)]
The pipeline
F# appears to have all this complicated syntax, with |> <| >> << and so on. But, these operators are defined in F# code, and follow some basic rules. They aren't magic or have any special compiler support.
The most important function operator is |>. A quick search of the F# source shows: C:\Program Files\FSharp-1.9.6.2\source\fsharp\FSharp.Core\prim-types.fs(2062): let inline (|>) x f = f x
(Operators are surrounded in parentheses to define them and to use them as functions with prefix notation.) The type signature is: > (|>);; val it : ('a -> ('a -> 'b) -> 'b) = <fun:clo@23>
This is "alpha to a function alpha to beta to beta". That probably didn't help. Perhaps looking at the type of function application will help:
> let apply f x = f x;; val apply : ('a -> 'b) -> 'a -> 'b
This demonstrates that a function application is really just taking a function "alpha to beta", giving it an alpha, and getting a beta. [I'm open to suggestions on better ways to pronounce type arguments.]
So, glance back up at the pipeline operator. We can see it's really just function application _in reverse_. What is the use of such a construct? If you've used C# 3.0's LINQ extension methods or a Unix shell, you probably already know. By reversing the function application, we can write things in a much more natural order. To modify something from the F# Quick Tour:
> let filterTypes name = - System.AppDomain.CurrentDomain.GetAssemblies() - |> Seq.map (fun a -> a.GetTypes()) |> Seq.concat - |> Seq.map (fun a -> a.Name) - |> Seq.filter (fun s-> s.Contains name);;
val filterTypes : string -> seq<string>
> filterTypes "Coll";; val it : seq<string> = seq ["ICollection"; "EvidenceCollection"; "GCCollectionMode"; "CollectionBase"; ...] >
Now, this is a bit embarrassing, but this took me a long time to get. I stared at this and re-read the F# manual for probably an hour. How could something so simple do such "complex" stuff?? Once I finally got used to the idea of functions being normal values, and the whole "one arg one value" bit, it snapped together. The other operators (<|, >>, <<) are pretty easy to follow once the basics are understood (going through prim-types.fs is a great experience).
What else? I hope this all helps fit some pieces together. Feel free to use the MSN thing on the side of my site to ask questions or give me suggestions. Thanks!
Edit: Also check out F# function types: fun with tuples and currying (From an F# team member's blog.)
|
|
Code | FSharp
|
Monday, November 03, 2008 9:07:15 PM UTC
|
Trackback
|
 Tuesday, October 28, 2008
Compiling for Silverlight 2 is a bit of a pain still. It's even worse with F#, because the Silverlight project system cannot tell when you're building your F# components correctly (using the right flags). So you get this error:
--------------------------- Microsoft Visual Studio --------------------------- You can only add project references to other Silverlight projects in the solution. --------------------------- OK ---------------------------
This happens even if you set up the F# compiler options correctly by adding: --standalone --noframework --cliroot "C:\program Files\Microsoft Silverlight\2.0.31005.0"
It still happens if you reference the DLL directly (FSLib1\bin\debug), you get the same error! Apparently VS or Silverlight projects go and try to find the project relating to the DLLs when you add a reference. So, the solution is easy: Move the DLL somewhere else. Then you can add a file reference, and it will work just fine.
One more problem. I get an FSC error when I turn optimize code on: C:\test\SilverlightApplication1\FSC(0,0): error FS0193: internal error: the module/namespace 'System' from compilation unit 'mscorlib' did not contain the namespace, module or type 'MarshalByRefObject'
If I leave optimize code off, then it seems to work. Good luck.
http://stackoverflow.com/questions/237044/how-does-silverlight-determine-an-assembly-is-silverlight
|
|
FSharp
|
Tuesday, October 28, 2008 10:27:50 PM UTC
|
Trackback
|
 Friday, September 19, 2008
In a previous comment, someone mentioned the OO mindset ("mold" -- quite appropriate). I don't want to go into it much, but simply "quote for win" something from here http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html. It's a nice take on things and I got a kick out of it:
" The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures."
Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.
On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.
"
|
|
Code | FSharp | Humour
|
Friday, September 19, 2008 6:00:50 PM UTC
|
Trackback
|
 Wednesday, September 17, 2008
Something I've heard often is that "F# is too complex/functional programming is too hard". This is something that sorta came up in the comments here: http://www.atrevido.net/blog/2008/09/16/Why+NOT+F.aspx.
Why is this irrelevant? You only learn a language once. You pay the learning curve cost one time; after that, you have the techniques and power at your disposal. However, you pay the cost of code every time you read or write it. Since I'm going to read and write a lot more code than number of languages I learn, I'd much, much, prefer to pay this overhead once, up front, rather than in my code each time.
Of course, it's not necessarily this simple. It's possible to design a powerful language that renders code even more difficult. Regular expressions are perhaps a nice example of this; they're often called "write only" code. Every time I do a non-trivial regexp, I'm always going back to the reference. Another example are C macros -- text-based, they quickly let you get into trouble. The design of C# runs away from this and tries to make it very difficult to write code that is "hard" to figure out -- if there's any edge case where a feature might be confusing or not work, C# tends to not allow it at all.
F# design is different. F# doesn't try to shelter users - it gives you tools and lets you decide how to use them. It makes the assumption that if you're writing a program, *you have some clue of what you're doing*. F#'s tools are still safe (compared to say, C), but sure, you can go create a mess if you'd like.
Poor code quality is *not* something that should be fixed solely via technical measures. I liken it to using web filters to make sure "employees aren't goofing off on the Internet" -- this is a policy/management issue and should be solved via administrative means. If one of my devs is spending all day on 4chan but gets work done and adds value, what do I care? Similarly, if the code quality coming out is acceptable and the solutions work correctly, I don't care if it used macros, custom operators, "difficult" code, etc. The process to make sure code quality is high (code reviews) will take care of anyone abusing language features in stupid ways.
But in truth, F# isn't actually much more complex to use. To the beginner, what seems to be "unnecessary terseness" and a lot of complicated syntax is actually a very basic system in action. Many of the "built-in" F# features such as the |> pipeline operator are defined right in the language itself. There's no magic going on -- you can create your own functionality in exactly the same way. Once you understand the basic rules, you'll see that most everything else follows them.
But at any rate, why is "easy to learn" a benefit? Sure, it's handy to promote a language if people can pick it up easily, but it's not indicitive of long-term power. True, if you have a "web developer" who's going to add a few server-side scripts, it's nice that he doesn't have to learn much. But if you're developing an application of any substance, I fail to see how these help, given the negative effects of having a "simple" language.
P.S. On my site I'm not trying to infer that F# will take over the world or that C# will go away. I've met too many "professional developers" to realise that anything that requires thinking isn't going to achieve stellar adoption. I'm simply pointing out that the reasons come down to apathy and intelligence (with respect to the learning curve; there could be other reasons as well), regardless of how politically correct one phrases it.
|
|
Code | FSharp
|
Wednesday, September 17, 2008 8:49:06 PM UTC
|
Trackback
|
 Tuesday, September 16, 2008
This is actually an open request for comments. I'm honestly interested in hearing why F# is not always the better candidate versus C#. What can C# do well that F# cannot? In nearly everything, F# seems to come out on top, as far as I can see.
Let's get these out of the way:
- Personal preference. Enough said. - In beta. Enough said. - Legacy code. Sure, if you have a project in C#, it may not make too much sense to switch mid-way. - Management. Enough said. - No benefit. This is simply lack of education and needs to be addressed separately. - F#'s too hard/it's hard to hire F# devs. This is a non-issue that is a separate topic. In summary, anyone worth hiring for C# work should be able to handle F#. [Exception being a very small deadline with an existing team...]
The only code reason I've seen is heavy native interop/pointer work. F# seems to be slightly more verbose than C# in this case. It's not much more, but I could see if you're doing just pointer code then it could get annoying. (Interestingly enough, F# COM interop is much nicer than C# because it supports named and optional parameters (http://blogs.msdn.com/dsyme/archive/2008/05/02/full-release-notes-for-f-1-9-4.aspx, search for "chart")...)
What other reasons are there for C# over F#?
Edit: Good point in the comments about C# being a standard with open source implementations. That could be a big issue for some. Another good point is the current lack of tool support (like ClickOnce, ASPX and WPF designers, etc.). I don't see any intrinsic reason F# wouldn't have those, except for limited resources.
|
|
Code | FSharp
|
Tuesday, September 16, 2008 5:06:28 AM UTC
|
Trackback
|
 Tuesday, September 02, 2008
|
There are other great books out there such as Expert F#.
The F# Dev center has links to many other "learn F#" articles. All of
these are great.
But, something I found helpful is going "purely functional", and
Haskell is the perfect vehicle. When you're forced to think only functional,
and don't have the other "escapes" F# has, you bend your mind into
understanding how you can accomplish things without using mutation or
object-orientation.
The downside of Haskell is that many resources seem to be very challenging to
get into. There's no doubt that the learning curve for Haskell can be tough. On
top of that, many materials tend to dive right into monads and it tends to end
up too scary. I've even bought several other good books on functional
programming, but none of them were easily approachable. (They have good
content, but you can't start from zero by using them.)
Enter Real World Haskell. This
is a *very* easy to follow book and really drives functional programming home.
It doesn’t assume you know anything about functional programming at all, so the
learning curve is a gentle slope.
Even better? It's completely available online, so you can
start reading it right
now! Plus, it has reader-submitted comments which are of tremendous use, as
they ask and answer many common questions that might arise as you read along,
without interfering with the flow. You can read the entire book here: http://book.realworldhaskell.org/read/
[But buy it to support the excellent work the authors have done!]
I've found that my F# skills have gone up tremendously by reading Real World
Haskell. For instance, I "sorta" understood F#'s computation
expressions and builder. Say, enough to use them -- that's easy, like most
things in F#), but understanding the concepts behind them? Starting to learn
Haskell really brings the understanding around. This isn't to say that you'll
eschew mutation and OO in F# -- such concepts can be very useful (and increase
performance on the CLR). But at least you'll know when a more elegant solution
is available.
(Plus, it's fun! As someone in #haskell on freenode put it to me:
"Learning Haskell will f*ck with your brain, and you'll like it.")
|
|
Code | FSharp
|
Tuesday, September 02, 2008 4:00:06 AM UTC
|
Trackback
|
 Sunday, August 31, 2008
Many times when I talk to a pro-dynamic typing person, they bring up duck typing. And when I say that duck typing could be resolved statically, I usually get wierd looks, or worse. Well F# exposes static duck typing to users. At least, using the definition that C# uses for duck typing of foreach and collection initalizers. (Yes, of course its a compiler feature and not true CLR/runtime checking.) I'm not promoting this, just pointing it out for fun.
F# allows inline values to accept "statically resolved type
variables". The F# specification says (§5.1.2):
A type of the form ^ident is a statically resolved variable type. A fresh type inference variable is created and added to the type inference environment (see §14.6). This type variable is tagged with an attribute indicating it may not be generalized except at inline definitions (see §14.7), and likewise any type variable with which it is equated via a type inference equation may similarly not be generalized.
At the end of this post I have a simple example to help understand this kind of type variable. But more interesting is a another constraint you can apply to such type variables. §5.1.5.3 Member Constraints: "A constraint of the form (typar or ... or typar) : (member-sig) is an explicit member constraint." But, inside the the F# library, this form is used with function application! For example, the char function is defined:
let inline char (x: ^a) = (^a : (static member ToChar: ^a -> char) (x)) // Function application! ...<snip /> -- I removed all the special case and inline IL code as its irrelevant for this post
Well, if we have member constraints with function application... we have "statically typed duck typing":
let inline speak (a: ^a) =
let x = (^a : (member speak: unit -> string) (a))
printfn "It said: %s" x
let y = (^a : (member talk: unit -> string) (a))
printfn "Then it said %s" y
type duck() =
member x.speak() = "quack"
member x.talk() = "quackity quack"
type dog() =
member x.speak() = "woof"
member x.talk() = "arrrr"
let x = new duck()
let y = new dog()
speak x
speak y
Outputs:
It said: quack Then it said quackity quack It said: woof Then it said arrrr
The restriction is that you have to use inline to get generalization*. If it's not inline, then it'll add additional constraints based on usage. If you removed inline in this case, you'd get the following:
warning FS0064: This construct causes code to be less generic than indicated by the type annotations. The type variable 'a has been constrained to be type 'duck'. error FS0001: The type 'dog' is not compatible with the type 'duck'.
Inline is as it sounds - the IL code is emitted inline, which is obviously a drawback in many cases. But that's the only way it can work - it has to statically know what types and compile the right method info into the binary. I suppose it'd be possible for the CLR to support this intrinsically. That way, the JIT could emit much more optimized code, versus creating a new method for reach type. I don't know dynamic languages well enough to know if this would be at all a help for interop.
*Here's a simple example to demonstrate the difference between 'a and ^a type parameters generalization.
> let id (a : 'a) = a;; val id : 'a -> 'a
> id 1, id "hi";; val it : int * string = (1, "hi") // Good, it's generic
> let id (a : ^a) = a;; let id (a : ^a) = a;; -------------^^ stdin(8,14): warning FS0064: This construct causes code to be less generic than indicated by the type annotations. The type variable 'a has been constrained to be type 'obj'.
val id : obj -> obj
> id 1, id "hi";; val it : obj * obj = (1, "hi") // Constrained to obj - not generic
> let inline id (a : ^a) = a;; val inline id : ^a -> ^a
> id 1, id "hi";; val it : int * string = (1, "hi") // Since it's inline, it's generic
|
|
FSharp
|
Sunday, August 31, 2008 1:14:34 AM UTC
|
Trackback
|
 Saturday, August 30, 2008
I find myself using "Comment Selection" often as I hack up quick scripts. Before the F# CTP, doing "Comment Selection" (Ctrl-K, Ctrl-C) would simply add (* *) around the selection. This makes it hard to uncomment specific lines. Now it goes and adds // in front of each line. Small things like this, in aggregate, decide a great IDE. For as much as I dislike some C# language decisions, their code editor is the best of anything I've ever seen.
Oh yea, the IntelliSense is also now WAY better. What's still missing is the "always active autocomplete", although I suspect this is harder in F#'s #light syntax than in C#.
|
|
FSharp
|
Saturday, August 30, 2008 6:10:59 PM UTC
|
Trackback
|
 Friday, August 29, 2008
Came across this: http://michaelcurbanski.com/log/2008/08/29/functional-programmers-hate-events/
His main point is that async total sucks, but that "Events don’t necessarily make async code tragically unreadable!" As a demonstration, he shows some simple async HTTP code without full or exception continuations. His code just enforces my point.
At any rate, yes, sure, if your continuation code isn't too related to your calling code, events can work. I mentioned this in my post: "events are a bad choice for code that is not loosely coupled" followed with "sometimes a simple delegate field would be a better choice". Indeed, looking at Mike's sample code, it seems as if using a simple delegate field would allow some nice refactoring.
But a point of the Event-based Asynchronous Pattern is, and I quote, to "Wait for resources to become available without stopping ("hanging") your application". So basically, you want to take an existing method, say, in response to a user action, but you can't let it block. This is exactly perfect for a continuation based approach and not so much for a loosely-coupled event-based approach. The act of "firing" an event should indicate that you're letting _other listeners_ (notice the plural) know when you did something.
More on when events are appropriate: Say you're listening for SNMP messages and when you receive one, you let "everyone" know that you did. You don't care what they do with the result, and they just go off on their own. Events can work. Or, take, for example, the BackgroundWorker. The BackgroundWorker doesn't help thread your blocking code, it just pushes the block to a background thread you don't care about. Your HTTP code will still be all sync, and you'll still burn a thread. BackgroundWorker main help is that it coordinates back to your "UI" thread, since many UI frameworks have strong thread affinity and will crash otherwise.
But that was the whole point The event async pattern, specifically in things like Silverlight, is completely aimed at *not letting the thread block*. That's the _only_ problem it is trying to solve. Silverlight only forces this because the main thread is the UI thread, and they won't want the browser hanging by dumb apps that don't put the block on a background thread. If they didn't want to do continuations, they could have at least kept the sync APIs, and thrown an exception if called from the main thread (thus letting people who know what they're doing not have to deal with the ugly event syntax).
BTW, F# kicks the crap out of your language I didn't mention it in my previous event post, but F#'s computation expressions let you deal with continuations in a totally sexy way. H.H. Don Syme, writes about it here: Introducing F# Asynchronous Workflows. You learn F# if you don't know it. But just to demonstrate, here's an example from that introduction:
let AsyncHttp(url:string) =
async { // Create the web request object
let req = WebRequest.Create(url)
// Get the response, asynchronously
let! rsp = req.GetResponseAsync()
// Grab the response stream and a reader. Clean up when we're done
use stream = rsp.GetResponseStream()
use reader = new System.IO.StreamReader(stream)
// synchronous read-to-end
return reader.ReadToEnd() }
The let! binding handles things asynchronously; the rest of the body becomes a continuation. If that isn't superior to any C# approach and doesn't make async easy, I don't know what would.
|
|
Code | FSharp
|
Friday, August 29, 2008 9:03:55 PM UTC
|
Trackback
|
A huge thank you and congratulations to MSRC and the F# team! (And to MSFT in general for taking their commercial languages up quite a few notches.)
http://blogs.msdn.com/dsyme/archive/2008/08/29/detailed-release-notes-for-the-f-september-2008-ctp-release.aspx
I was up late last night reading different things on MSR and came across Andrew Kennedy's page. What a surprise to see this morning that F# includes Units of Measure Inference and Checking. http://research.microsoft.com/~akenn/units/intro.html Edit: Oh cool, Mr. Kennedy now has a blog and goes into detail: Units of Measure in F#: Part One, Introducing Units
It seems they did a ton of general clean up and added consistency with .NET and so on. (For instance, you don't need to explicitly accept subtypes with #.)
There's also an "AutoOpen" feature for modules, which allows modules to automatically get opened if their container namespace is -- I suppose this allows more namespace oriented development like .NET prefers.
Too much stuff to understand the full impact just by browsing the release notes. I think the license has changed; at least it's quite clear that our commercial plans with F# are perfectly allowable (there was some question before). So, now it gets interesting...
|
|
FSharp
|
Friday, August 29, 2008 7:19:13 PM UTC
|
Trackback
|
 Wednesday, August 27, 2008
Been meaning to write this for a while, and I think I touched on it here, but I'd like to expand a bit. C# Extension Methods are
just a hack to compensate for C#'s poor handling of functions in general. As
far as I can tell, they were added solely so you can do this type of thing in
LINQ:
var squares = myInts.Select(i
=> i * i)
Instead of:
var squares =
Enumerable.Select(myInts, i => i * i)
In other words, they wanted to provide some simple infix syntax for functions.
Well, that's a poor approach to the problem.
- First off, it only works on
function specially declared to be "extensions", which means your
composition options are limited to whatever the library has built in. I can't
send arguments to arbitrary static methods, like, say, "someVar.Console.WriteLine".
- Second, since extension methods are defined solely by their method name,
ambiguity is quite easy to come across. There's no way to qualify Foo.Function versus Bar.Function.
Pipeline
Other languages approach this with two simple things (which actually simplify
the entire language/type system overall). First off, we need to be able to
define function operators. I'll demonstrate with F#'s pipeline operator:
let (|>) x f = f
x
[As a side note, any language that lets you toss around
operators and functions will allow this kind of syntax – it isn’t that F# had
to have compiler support for this particular operator.]
In fake C#,
it’d be something like (for fun, notice the lack of type inference):
B
operator|> <A, B>(A x, Func<A, B> f) { return f(x); }
This means that the |> operator will take x on the left and apply it to f on
the right side. If this existed in C#, you'd be able to write something like:
"Hello"
|> Console.WriteLine
or
if (myInts |>
Enumerable.Any) { .... }
Now we can pass in a parameter to static methods. But, hey,
whaddya know? With this, Extension Methods are solved for all single-argument
static methods! That was easy. But what about Select – it takes two parameters,
so this won’t work.
Enter the Lambda
What if ALL functions took one parameter and output one parameter? If that were
the case, then we’d be set. But how do allow more than one parameter? Well,
what if, every time you declared a method with more than one parameter, it
actually returned a method that took the next parameter? For example, we could
write “Add” as:
Func<int,int>
Add(Func<int,int> a) { return b => a + b; }
This is known as the curried form of Add. We’d now call it
as: Add(5)(6). We can do cute stuff like “var inc = Add(1)”. But, as the Add
declaration shows, in C# this is too unwieldy (and this is a simple example!).
The compiler should actually do all this for us, so we can just write our
functions normally but use them as if they were written in curried form.
Now, if we simply swap the order of arguments for
Enumerable.Select, we have our extension method ready to roll: Enumerable.Select(Func,
IEnumerable) can be used so:
var squares = myInts |>
Enumerable.Select(i => i * i)
Now the call to Select takes the lambda (i * i) and returns
a function that takes an Enumerable. It is then given the myInts, and
everyone
is happy. This is just a quick, crap, explanation. Google can lead you
to many more interesting resources about partial application, currying
and so on.
At
any rate, I think if C# had taken this approach, we'd all be much
better off. To top it off, more functions would take their arguments in
a proper style. As it is, uncurried versions of Extension Methods are
incompatible with normal function pipelining. Oh well.
|
|
Code | FSharp
|
Wednesday, August 27, 2008 12:17:53 AM UTC
|
Trackback
|
 Saturday, August 16, 2008
|
#light open System
type 'a ImmutableStack = | Empty | Stack of 'a * 'a ImmutableStack member x.Peek() = match x with | Stack (v, _) -> Some v | _ -> None member x.Pop() = match x with | Stack (_, s) -> s | _ -> failwith "empty stack" member x.Push a = Stack(a, x) member x.IsEmpty = x = Empty
(Well, I'd probably just use a list in most cases.) But interestingly, he has an All function, which returns a sequence of the entire stack. Chris suggested using sequence expressions and then recursively calling the function:
member x.All = match data with | Empty -> Seq.empty | Value (v,n) -> seq { yield v yield! n.All }
This is pretty nice as far as syntax goes. For some reason, I wanted to see how it'd look without the recursion (which needs to generate a new enumerator, unless the compiler is doing some wicked awesome stuff, which wouldn't surprise me). Here are some of the things I came up with:
member x.All1 = let until f = Seq.generate (fun () -> ref x) f (fun _ -> ()) until (fun cur -> match (!cur) with | Stack(v, s) -> cur := s Some v | _ -> None)
Seq.generate continues calling the function until None is returned, so this provides the loop termination. Another similar approach:
member x.All2 = let until f = Seq.generate (fun () -> ref x) f (fun _ -> ()) until (fun cur -> try (!cur).Peek() finally if not (!cur).IsEmpty then cur := (!cur).Pop())
Since Peek already returns 'a option, we can use it directly. The problem is that we need to update cur to cur.Pop
and then return a value. The try/finally works, but the whole deal still doesn't seem very elegant. Sequence expressions allow us to yield:
member x.All3 = let cur = ref x { while not (!cur).IsEmpty do yield (!cur).Peek() do cur := (!cur).Pop() } |> Seq.choose(fun x -> x)
I dislike this one. Because we're not doing the pattern match ourselves, we end up yielding 'a option. But None is never valid because we guard on IsEmpty. This makes us stick a Seq.choose on with an identity function to strip off the Some. [Side note, is there no built-in identity function?] Bringing the match into the seq fixes the issue, but the code is pretty long:
member x.All4 = let cur = ref x { while not (!cur).IsEmpty do match (!cur).Peek() with | None -> do () | Some v -> do cur := (!cur).Pop() yield v }
I think what bothers me the most here is that the while and match are redundant. The None case will never be matches because we guard on IsEmpty. Moving that into a separate function gives:
member x.All5 = let v = function Stack(vl, _) -> vl | _ -> failwith "dont call on empty" let cur = ref x { while (!cur) <> Empty do yield v (!cur) do cur := (!cur).Pop() }
I prefer All5 to All4, but still think All1 or All2 are nicer. (Chris's original is best as far as I can tell.) How else can this be done?
Edit: I lost sight of one of the principals of functional programming: Composition. Here's a simple update to All5 that, IMHO, vastly improves it:
member x.All6 = let cur = ref x let toVal = function Stack(v, _) -> v | _ -> failwith "dont call on empty" let next () = try toVal (!cur) finally cur := (!cur).Pop() { while (!cur) <> Empty do yield next () }
Every line builds up and you don't have to keep its details "active" in your mind. This makes the sequence expression (which is the driver of the algorithm) easy to verify. And again, to clarify, in a real system I'd probably use what Chris suggested since it's the nicest syntax. The other versions are only seeing what it looks like if we toss recursion and use a reference cell.
|
|
Code | FSharp
|
Saturday, August 16, 2008 4:09:49 AM UTC
|
Trackback
|
 Thursday, June 26, 2008
|
In my last post, I said I'd write the sample in C# to compare to F#. Well, I grossly underestimated the power of query comprehensions. The C# version is almost the same length (formatting differences, mainly). I'm surprised and impressed. (Or maybe I'm writing F# like I'd write C#.) Edit: I think maybe sequence expressions could cut it down a bit...
...But... C# still can't do discriminated unions efficiently or effectively ;).
1 // crudcreatecompare.cs: Generates LINQ CRUD table fields using the horribly named DatabaseBase code
2 //
3 // Tables look like: [Table(Name="dbo.Accounts")]
4 // Columns look like this:
5 // [Column(Storage="_AccountName", DbType="VarChar(128) NOT NULL", CanBeNull=false, IsPrimaryKey=true)]
6 // [DataMember(Order=1)] // Exists if serialization is turned on; used to order key parameters
7 // Emits:
8 // public static readonly TableHelper<Account, String> Accounts =
9 // CreateTable(dc => dc.Accounts, a => a.AccountName);
10
11 using System;
12 using System.Collections.Generic;
13 using System.Data.Linq.Mapping;
14 using System.IO;
15 using System.Linq;
16 using System.Reflection;
17 using System.Runtime.Serialization;
18
19 class Program
20 {
21 static void Main()
22 {
23 Console.WriteLine(
24 new Program().generate(
25 "C:\\yourlinq.dll"));
26 }
27
28 string generate(string asmpath)
29 {
30 var asm = Assembly.LoadFrom(asmpath);
31 var lines = from t in asm.GetExportedTypes()
32 let ta = getAttr<TableAttribute>(t)
33 where ta != null
34 let name = pluralize(ta.Name.Replace("dbo.", ""))
35 orderby name
36 select genTable(t, name);
37 return joinStrings("", lines);
38 }
39
40 string genTable(Type t, string tableName)
41 {
42 var keyProps =
43 from p in t.GetProperties()
44 let c = getAttr<ColumnAttribute>(p)
45 where c != null && c.IsPrimaryKey
46 let dm = getAttr<DataMemberAttribute>(p)
47 orderby dm == null ? 0 : dm.Order
48 select p;
49 var tw = new StringWriter();
50 tw.WriteLine("public static readonly TableHelper<{0}, {1}> {2} =",
51 t.Name,
52 joinStrings(", ", keyProps.Select(p => p.PropertyType.Name)),
53 tableName);
54 tw.WriteLine("\tCreateTable(dc => dc.{0}, {1});",
55 tableName,
56 joinStrings(", ", keyProps.Select(p => "a => a." + p.Name)));
57 tw.WriteLine();
58 return tw.ToString();
59 }
60
61 string joinStrings(string sep, IEnumerable<string> items)
62 {
63 return string.Join(sep, items.ToArray());
64 }
65 string pluralize(string s)
66 {
67 return s.EndsWith("s") ? s : s + "s";
68 }
69
70 T getAttr<T>(ICustomAttributeProvider icap)
71 {
72 var a = icap.GetCustomAttributes(typeof(T), true);
73 return a.Length == 0 ? default(T) : (T)a[0];
74 }
75 }
|
|
Code | FSharp
|
Thursday, June 26, 2008 6:15:10 AM UTC
|
Trackback
|
|
With the DatabaseBase and TableHelper classes, you still have to generate a CreateTable field per table. Why do it by hand? I wrote an F# script to generate the statements. I must say, I'm loving F# more than I had hoped. The more I learn, the better it gets. I've noticed (even in C#) that using a functional style generally means less errors. This script worked without bugs the first time (i.e., as soon as it compiled), which is pretty cool (granted, it's not big, but I'm sure if I had tons of for loops, I woulda messed up somewhere). Maybe this weekend I'll try writing it in C# just to compare (pretty sure it'll be more than 59 lines!). And I'll preempt comments about readability: Yes, it may be difficult to read if you don't know F#, but more on that later...
I'd love feedback as to making it more "functional"; years of imperative programming don't die quickly. Also, I'm not very happy with the definition of chooseAttr, but I can't seem to get it to infer the type I want otherwise.
Anyways, here's the code. You'll need to specify the references when compiling: -r "C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Data.Linq.dll" -r "C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\System.Runtime.Serialization.dll"
1 // crudcreatetable.fsx: Generates LINQ CRUD table fields using the horribly named DatabaseBase code
2 //
3 // Tables look like: [Table(Name="dbo.Accounts")]
4 // Columns look like this:
5 // [Column(Storage="_AccountName", DbType="VarChar(128) NOT NULL", CanBeNull=false, IsPrimaryKey=true)]
6 // [DataMember(Order=1)] // Exists if serialization is turned on; used to order key parameters
7 // Emits:
8 // public static readonly TableHelper<Account, String> Accounts =
9 // CreateTable(dc => dc.Accounts, a => a.AccountName);
10
11 #light
12 open System
13 open System.Reflection
14 open System.Data.Linq.Mapping
15 open System.Runtime.Serialization
16
17 let getAttr<'target, 'a when 'a :> ICustomAttributeProvider> (ty : 'a) =
18 match List.of_array (ty.GetCustomAttributes(typeof<'target>, true)) with
19 | a::_ -> Some (a :?> 'target)
20 | [] -> None
21 let chooseAttr<'target, 'a when 'a :> ICustomAttributeProvider> (ty : 'a) =
22 match getAttr<'target,_> ty with
23 | Some(a) -> Some(ty,a)
24 | None -> None
25
26 let joinStrings (sep:string) items = items |> Seq.fold1 (fun acc x -> acc + sep + x)
27 let pluralize (name:string) = if name.EndsWith("s") then name else name + "s"
28
29 let generate(asmpath:string) =
30 let genTable (t:Type, tableName) =
31 let keyProps =
32 t.GetProperties()
33 |> Seq.choose (chooseAttr<ColumnAttribute,_>)
34 |> Seq.filter(fun (p,c) -> c.IsPrimaryKey)
35 |> Seq.map(fun (p,_) -> p, getAttr<DataMemberAttribute, _> p)
36 |> Seq.orderBy(function | _,Some(dm) -> dm.Order | _ -> 0)
37 |> Seq.map (fun (p,_) -> p)
38 let tw = new IO.StringWriter()
39 let pn fmt = Printf.twprintfn tw fmt
40 pn "public static readonly TableHelper<%s, %s> %s ="
41 t.Name
42 (joinStrings ", " (keyProps |> Seq.map (fun p -> p.PropertyType.Name)))
43 tableName
44 pn "\tCreateTable(dc => dc.%s, %s);"
45 tableName
46 (joinStrings ", " (keyProps |> Seq.map (fun p -> "a => a." + p.Name)))
47 pn ""
48 tw.ToString()
49
50 let asm = Assembly.LoadFrom asmpath // Don't use ReflectionOnly 'cause it won't resolve dependencies
51 asm.GetExportedTypes ()
52 |> Seq.choose (chooseAttr<TableAttribute,_>)
53 |> Seq.map (fun (t,ta) -> t, ta.Name.Replace("dbo.", "") |> pluralize)
54 |> Seq.orderBy (fun (t,_) -> t.Name)
55 |> Seq.map genTable
56 |> Seq.fold1 (+)
57
58 generate "C:\\yourlinq.dll"
59 |> Console.WriteLine
|
|
FSharp
|
Thursday, June 26, 2008 5:13:44 AM UTC
|
Trackback
|
|
|