Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ocaml destructive substitution error

Tags:

module

ocaml

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'm getting this error while trying to substitute 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 r' type ?

like image 200
juloo65 Avatar asked May 03 '26 06:05

juloo65


1 Answers

This is a limitation of the destructive substitution - you can substitute only with a type constructor that has syntactically the same type parameters, not with arbitrary type expression. It is not a fundamental limitation, as you can easily work around it, as you have shown in your example.

There is, however, some sort of a code repetition there, that you can get rid of by using an abstraction (on the type level). In OCaml, you can use functors to create type-level abstractions, i.e., functions that take types and return types. The syntax is a little bit heavy, but with the properly chosen names and signatures, it can be fine.

Let's write the Loop abstraction, that will construct 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 the destructive substitution, as F(T).t is a type constructor without parameters, e.g.,

 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 drawback is that you need to define the Types module since you can't construct modules directly in the functor application in a module signature.

Of course, in your case, the solution is much bigger, than what you proposed, so, probably, it is better to use yours. But in case if you definitions are big, you can use functors.

like image 179
ivg Avatar answered May 07 '26 09:05

ivg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!