Ocaml disruptive replacement error
type ('a, 'r) loop
type 'e task
type ('a, 'e) tmpl'
module type COMPONENT =
sig
type t
type event
type r
val update : t -> event -> r
val view : (t, event) tmpl'
end
module type MAIN_COMPONENT =
sig
type t
type event
type r
include COMPONENT
with type t := t
with type event := event
with type r := (t * event task option, r) loop
end
I am getting this error when trying to replace the type r
:
Error: Only type constructors with identical parameters can be substituted.
However, this works:
module type MAIN_COMPONENT =
sig
type t
type event
type r
type r' = (t * event task option, r) loop
include COMPONENT
with type t := t
with type event := event
with type r := r'
end
Why?
How can I get rid of the type r'
?
source to share
This is a limitation of destructive substitution - you can only replace with a type constructor that has syntactic parameters of the same type, not with an arbitrary type expression. This is not a fundamental limitation as you can easily work around it as you showed in your example.
There is, however, some code repetition that you can get rid of by abstraction (at the type level). In OCaml, you can use functors to create type-level abstractions, i.e. Functions that accept types and return types. The syntax is a bit heavy, but with the right names and signatures it can be fine.
Let's write an abstraction Loop
that builds a type (t1 * t2 task option, t3) loop
from the provided types t1
, t2
and t3
:
module type T3 = sig type t1 type t2 type t3 end
module Loop(T : T3) = struct
type t = (T.t1 * T.t2 task option, T.t3) loop
end
Given this definition, we can use destructive substitution because it F(T).t
is a parameterless type constructor, for example
module type MAIN_COMPONENT = sig
type t
type event
type r
module Types : T3 with type t1 = t
and type t2 = event
and type t3 = r
include COMPONENT
with type t := t
with type event := event
with type r := Loop(Types).t
end
The downside is that you need to define a module Types
as you cannot create modules directly in a functor app in the module signature.
Of course, in your case, the solution is much larger than what you suggested, so it's probably better to use yours. But in case of large values, you can use functors.
source to share