Luca Fülbier
Luca Fülbier

Reputation: 2731

Understanding F# documentation function signatures

I am currently learning F# with a free online resource. Since i am curious and try to apply the learned stuff in some small excercises, I find myself consulting the MSDN F# documentation quite often.

But the documentation seems really cryptic to me. Take this documentation page for the pown function for example. The usage is pretty straight forward, but i don't understand the functions signature:

// Signature:
pown : ^T -> int -> ^T (requires ^T with static member One and ^T with static member op_Multiply and ^T with static member (/))

Can someone explain to me, what the following things are about?

  1. What does the ^ (Circumflex) before the T do?
  2. What does "T" mean? Is it a generic type?
  3. What does the double -> do?
  4. What does the requires statements do?

I hope this isn't too much to cover in one answer.

Upvotes: 6

Views: 599

Answers (2)

scrwtp
scrwtp

Reputation: 13577

There are a few things going on there, so for starters, here's how I would suggest you approach signatures in F#. First of all, ignore the circumflex - mentally substitute a tick there. Then you can ignore the "requires" part - long story short, it's there because of the circumflex.

So after that you have a signature like this:

// Signature:
pown : 'T -> int -> 'T

'T is a generic type - uppercase 'T is a .NET standard, F# usually uses lowercase 'a, 'b etc. What this signature describes is a function that takes a 'T and an int, and returns a 'T. The type after the last -> is the "return type" of the function - at least that's a useful way to think about it at the beginning.

In reality, there's a bit more to that - in F# functions are curried (and partially applicable by default), so what you really have is a function that takes a 'T and returns a function of signature int -> 'T - at which point it's clear why you have double ->.

And the circumflex thing is a statically resolved type - I see @kvb gave more details on that already. It's good to be aware that it exists, but it's something that's rarely used in practice (you'll see it on core numeric functions and operators though).

Upvotes: 6

kvb
kvb

Reputation: 55184

  1. This indicates that T is a statically resolved type parameter as opposed to a normal generic type parameter (see also 4 below).
  2. Yes.
  3. -> is the type constructor for functions and is right associative, so this part is equivalent to ^T -> (int -> ^T). In other words, if you pass an argument of type ^T to this function, you'll get back a function from int to ^T. So pown 2 is the function 2x where the power hasn't been passed yet. And pown 2 8 is the same as (pown 2) 8: it's 28.
  4. At the point of invocation, whatever concrete type is substituted for ^T it must be statically known to meet these requirements. So you can call pown 2 8 (because int supports these operations), but not pown "test" 8 (because string doesn't).

Upvotes: 9

Related Questions