Today I was speaking with a colleague about some F#, and he pointed out a few gotchas with F# type signatures, especially if you’ve spent some time with Haskell (and not OCaml or other ML-ish language).
->
style function signatures please let me know.
The example we were looking at is Seq.unfold
, whose signature looks like this:
Apostrophes for type parameters
Any type prefixed with a '
character represents a type parameter (or generic type in C# parlance). For unfold
this means 'State
and 'T
can be any type. We can also write this in potentially more familiar .NET syntax:
A lot of the F# code I see follows a more Haskellish (?) convention of using lowercase type variable names, more like:
Asterisk for tuples
Types separated by a *
are tupled (or product types, which explains the *
symbol). For example, (1, "abc", Foo())
is of type int * string * Foo
.
So in unfold
, 'T * 'State
represents a tuple of 'T
and 'State
.
Postfix generic syntax
F# supports both .NET-style prefix generic syntax and ML-style postfix syntax. So instead of writing int option
, we can also write Option<int>
(both forms are equivalent). Which means we can re-write unfold
as:
Using unfold
With those things in mind, let’s use the unfold
signature to work out what it does.
Given a function that can take 's
values and return a tuple of an element and next 's
value or nothing, and a starting 's
, unfold
will generate a sequence of 't
values until the generator function returns None
(i.e. potentially infinite).
We could use this to generate a sequence of all the days since a starting date (infinite, at least until DateTime
hits DateTime.MaxValue
):
Translating to other languages
Finally, if you’re more familiar with C# or Haskell, here are my attempted translations:
Haskell uses lowercase type names for generics (instead of '
characters), while concrete types have uppercase names. It also uses the same syntax for tuple types as values, so (1,2) :: (Int, Int)
. For some odd reason, Haskell uses ::
for “type of” instead of a single :
.
The C# version is a bit messier due to having to use Func
instead of a shorthand for function types, and similarly for declaring tuple types. (I’ve also uncurried the C# version otherwise we end up with nested Func
types everywhere, and it is the more typical form for C# functions.)