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'

?

+3


source to share


1 answer


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.

+5


source







All Articles