First-class functions in F#, part 0

I wrote a while back about how F# makes it easy to work with functions, but this recent question on Stack Overflow reminded me that I hadn’t really talked about the fundamental difference between F#’s first-class functions and C#/VB’s delegates. In C# and Visual Basic, there are delegate types for all kinds of function signatures, but there’s no canonical function type. Whereas in F#, function types are part of the language.

Consider the following line of C#:

var isReticulated = delegate(Spline s) { return s.IsReticulated; };

As the Stack Overflow poster discovered, this doesn’t compile. Why not? Because although the right hand side is clearly a function from Spline to bool, C# doesn’t recognise that as a type. C# only recognises specific delegate types such as Func<Spline, bool>, Predicate<Spline> or Converter<Spline, bool>. So you have to pick one of these and spell it out:

Predicate<Spline> isReticulated = delegate(Spline s) { return s.IsReticulated; };

And woe betide you if you have to deal with APIs that have made different choices, because there’s no conversion between ‘compatible’ delegate types:

public Predicate<Person> GetFilter(FilterSpecification spec) { ... }
 
public IEnumerable<Person> GetFilteredPeople(FilterSpecification spec)
{
  var filter = GetFilter(spec);
  return _people.Where(filter);  // compiler error
}

The Where method demands a Func<T, bool>, so if all you have is a Predicate<T> then you’re stuffed, even though they’re both functions from T to bool! Instead you have to write a guffy little adapter:

return _people.Where(p => filter(p));  // everybody loves code noise

Contrast this with F#, in which functions do have a type:

let isReticulated = fun (s : Spline) -> s.IsReticulated

The compiler figures out the type as Spline -> bool. Which means you can pass this function to anything that expects a function from Spline to bool. You don’t need to worry about the difference between Funcs, Predicates, Converters and goodness knows what else: instead, function types are standardised at the language level.

let reticulatedSplines = List.filter isReticulated splines  // List.filter takes a 'T -> bool
let antifilter predicate list = List.filter (predicate >> not) list  // Compiler infers type of predicate as 'T -> bool
let unreticulatedSplines = antifilter isReticulated splines  // so isReticulated is compatible with antifilter

Any function with a function argument can work with any function with the right signature — not just ones that happen to have been packaged up into the right delegate type.

And that, at bottom, is why functions are first class in F#, and not in C# or Visual Basic.

Tagged as F#

6 Responses to “First-class functions in F#, part 0”

  • Intro to F#: First-class functions in F#, part 0…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

  • […] This post was mentioned on Twitter by Mindscape, Newsery 3. Newsery 3 said: Introduction to F#: First-class functions in F# – http://bit.ly/gMDV9z – [Hacker News FH] […]

  • Dont you think this is very similar to Function data type in Actionscript3? That was released long time before F#.

  • Hi Rocksoccer,

    I’m not familiar with ActionScript, but you’re right, first-class functions certainly aren’t original to F#. Pretty much every functional language has them: Lisp, JavaScript, Haskell and of course the OCaml language which is F#’s immediate ancestor. Since ActionScript is (if I understand correctly) a dialect of JavaScript, I’d assume it too has function types. (Of course, in Lisp and JavaScript, there aren’t function types enforced by the compiler as there are in Haskell, OCaml and F# — but the first-class-ness of functions is there all the same.)

  • I think doing this:

    Predicate isReticulated = delegate(Spline s) { return s.IsReticulated; };

    .. gives C# a poor image when you can just as easily do this:

    Predicate isReticulated = s => s.IsReticulated;

    This is much closer to, and as terse as, the F# version.

    Having said that, I’d much prefer to be using F# for this kind of stuff, for obvious reasons :)

    Cheers!

  • Hi OJ,

    That’s true, but I wanted the RHS to be as explicit as possible (lambdas drag in the whole expression tree ambiguity on top of the function type issue). And to be fair I did make F# look equivalently bad by choosing an example that required the ‘fun’ syntax *and* type annotations!

    However, terseness wasn’t really the point of the contrast — what I was trying to get at was that F# has canonical function types, whereas C# doesn’t. Both languages have a nice terse lambda syntax for creating function values, but only F# has language-level *types* for function values. Appreciate the feedback though!

  • Leave a Reply

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top