Reputation: 71033
I am trying to encapsulate the idea of "multiple passes" of a set of operations.
The idea is that if I run a set of operations, they will produce a new set of operations, those will get run, producing a third set which are then run, and so on. Obviously, there is the danger the algorithm won't terminate, but who cares.
I tried to model it with:
type Op = Unit -> Op option
let rec performPass (ops : Op list) : Unit =
ops |> List.choose (fun x -> x ()) |> performPass
The idea was that I could write functions like:
let firstPass () =
// Perform state-changing first-pass
Some (fun () ->
// Perform state-changing second-pass
Some (fun () ->
// Third pass is the last
None))
But was quickly informed that this is an infinite type. Upon reflection, I agreed that it's infinite but struggled to find another way to represent this.
So, how would you encapsulate a multi pass algorithm where the previous pass generates the code for the next pass?
Upvotes: 1
Views: 57
Reputation: 243096
The F# compiler does not like immediate recursion in type aliases, but it will happily let you define a recursive type when you define it as a new type - for example, using single-case discriminated union:
type Op = Unit -> Op option // Type alias does not work
type Op = Op of (Unit -> Op option) // Single-case union is fine
Then you can update your functions as follows:
let rec performPass (ops : Op list) : Unit =
ops |> List.choose (fun (Op x) -> x ()) |> performPass
Here, the only change is that I turned fun x -> x ()
to fun (Op x) -> x ()
which uses pattern matching on the single case to extract the function from the Op
type.
let firstPass () =
// Perform state-changing first-pass
Some (Op (fun () ->
// Perform state-changing second-pass
Some (Op (fun () ->
// Third pass is the last
None))))
Here, I added Op
in a number of places to wrap the function inside the Op
type.
Upvotes: 2
Reputation: 71033
This is not the general solution, but one fix is to simply limit it to 3 passes:
type Op1 = Unit -> Op2
and Op2 = Unit -> Op3
and Op3 = Unit -> Unit
let rec performPasses (ops1 : Op1 list) : Unit =
let apply x = x ()
ops1 |> List.map apply |> List.map apply |> List.map apply |> ignore
Upvotes: 0