Can I express recursive generic type relationships with type constraints in F #?
Given the following type
type WorkflowStep<'next, 'prev, 'cancel> =
abstract member Next : unit -> 'next
abstract member Prev : unit -> 'prev
abstract member Cancel : unit -> 'cancel
I would like to express the fact that 'next
, 'prev
and 'cancel
must also be of type WorkflowStep
or type unit
, is it possible to code at the type level using F #?
If your description is missing some details that would make it impracticable, there is a fairly simple encoding that doesn't even require the type to be generic:
type Transition =
| Step of WorkflowStep
| Done
and WorkflowStep =
abstract member Next : unit -> Transition
abstract member Prev : unit -> Transition
abstract member Cancel : unit -> Transition
where Transition
captures your requirement for WorkflowStep
either doing another step or the value of one. This gives you a kind of flipped CPS-like flow control mechanism.
It's impossible. If this were implemented, it would mean that the workflow itself would contain an endless sequence of generics, which is unfortunately not supported in f #.
Below is a more detailed explanation of why using a simplified version of your workflow type is given above.
//error workflow must be provided a type
type Workflow<'t when 't :> Workflow<_>> =
abstract member Next : unit -> 't
However, when we specify a type parameter for the returned workflow, it now requires 2 parameters to apply.
//workflow now requires 2 parameters
type Workflow<'nextvalue, 't when t:>Workflow<'nextvalue>>
abstract member Next : unit->'t
It's easy to see that to create a Workflow class, we need an infinite number of common arguments that f # doesn't support.
One alternative is to specify that your workflow type can only run on one workflow, if your resulting code looks something like this.
type Workflow<'value> =
abstract member Next : unit -> Workflow<'value> option
abstract member Prev : unit -> Workflow<'value> option
abstract member Cancel : unit -> Workflow<'value> option
The parameter type you see above allows you to return either a value (Some) or one (None)
Note that this type of type list has a name and is implemented in some language called a variation type.