Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No F# generics with constant "template arguments"?

Tags:

f#

It just occurred to me, that F# generics do not seem to accept constant values as "template parameters".

Suppose one wanted to create a type RangedInt such, that it behaves like an int but is guaranteed to only contain a sub-range of integer values.

A possible approach could be a discriminated union, similar to:

type RangedInt = | Valid of int | Invalid

But this is not working either, as there is no "type specific storage of the range information". And 2 RangedInt instances should be of different type, if the range differs, too.

Being still a bit C++ infested it would look similar to:

template<int low,int high>
class RangedInteger { ... };

Now the question, arising is two fold:

  1. Did I miss something and constant values for F# generics exist?
  2. If I did not miss that, what would be the idiomatic way to accomplish such a RangedInt<int,int> in F#?

Having found Tomas Petricek's blog about custom numeric types, the equivalent to my question for that blog article would be: What if he did not an IntegerZ5 but an IntegerZn<int> custom type family?

like image 841
BitTickler Avatar asked Sep 16 '15 07:09

BitTickler


2 Answers

The language feature you're requesting is called Dependent Types, and F# doesn't have that feature.

It's not a particularly common language feature, and even Haskell (which most other Functional programming languages 'look up to') doesn't really have it.

There are languages with Dependent Types out there, but none of them I would consider mainstream. Probably the one I hear about the most is Idris.

like image 191
Mark Seemann Avatar answered Oct 03 '22 22:10

Mark Seemann


Did I miss something and constant values for F# generics exist?

While F# has much strong type inference than other .NET languages, at its heart it is built on .NET.

And .NET generics only support a small subset of what is possible with C++ templates. All type arguments to generic types must be types, and there is no defaulting of type arguments either.

If I did not miss that, what would be the idiomatic way to accomplish such a RangedInt in F#?

It would depend on the details. Setting the limits at runtime is one possibility – this would be the usual approach in .NET. Another would be units of measure (this seems less likely to be a fit).

What if he did not an IntegerZ5 but an IntegerZn<int> custom type family?

I see two reasons:

  • It is an example, and avoiding generics keeps things simpler allowing focus on the point of the example.
  • What other underlying type would one use anyway? On contemporary systems smaller types (byte, Int16 etc.) are less efficient (unless space at runtime is the overwhelming concern); long would add size without benefit (it is only going to hold 5 possible values).
like image 40
Richard Avatar answered Oct 03 '22 23:10

Richard