# GADTs - avoiding type constructor escaping scope problems

**URL:** <https://discuss.ocaml.org/t/gadts-avoiding-type-constructor-escaping-scope-problems/7005>\
**Category:** Learning\
**Tags:** type-system, gadt\
**Created:** [December 21, 2020, 3:53pm UTC](https://discuss.ocaml.org/t/gadts-avoiding-type-constructor-escaping-scope-problems/7005 "2020-12-21T15:53:37Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![roddy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/roddy/32/2261_2.png) [@roddy](https://discuss.ocaml.org/u/roddy)\
**Post date:** [December 21, 2020, 3:53pm UTC](https://discuss.ocaml.org/t/gadts-avoiding-type-constructor-escaping-scope-problems/7005/1 "2020-12-21T15:53:37Z")

</div>

I’m trying to write a module with this signature:

```ocaml
  type t

  type ('input, 'output) handler = ('output -> unit) -> 'input -> unit

  type ('input, 'output) key

  val create : unit -> t

  val add : ('input, 'output) handler -> t -> ('input, 'output) key

  val link : source:('a, 'b) key -> target:('b, 'c) key -> t -> t

  val send : ('input, _) key -> 'input -> t -> unit

```

(the idea is to define a load of `handler` functions and connect them up in arbitrary ways, where each one may trigger and be triggered by any number of others, including recursively)

I tried this

```ocaml
  type t = Hmap.t ref

  type ('input, 'output) handler = ('output -> unit) -> 'input -> unit

  type _ target_key = Key : ('input, 'output) key -> 'input target_key

  and ('input, 'output) key =
    (('input, 'output) handler * 'output target_key list) Hmap.key

  let create () = ref Hmap.empty

  let add (handler : ('input, 'ouput) handler) t =
    let key = Hmap.Key.create () in
    t := Hmap.add key (handler, []) !t;
    key

  let link ~(source : ('a, 'b) key) ~(target : ('b, 'c) key) t =
    let map = !t in
    let handler, previous_targets = Hmap.get source map in
    t := Hmap.add source (handler, Key target :: previous_targets) map;
    t

  let rec send (key : ('input, 'output) key) (value : 'input) t =
    let map = !t in
    let handler, targets = Hmap.get key map in
    let emitter event_from_source =
      List.iter targets ~f:(fun target ->
          match target with
          | Key target -> send (Caml.Obj.magic target) event_from_source t)
    in
    handler (Caml.Obj.magic emitter) value

```

which does work, but it would be better not to have the `Obj.magic`s. Is there a way to avoid them? I can’t think of how to hide/expose the `'ouput` of the targets in a good way.

---

<div class="post-metadata">

**Author:** ![octachron](https://avatars.discourse-cdn.com/v4/letter/o/49beb7/32.png) [@octachron](https://discuss.ocaml.org/u/octachron)\
**Post date:** [December 21, 2020, 4:16pm UTC](https://discuss.ocaml.org/t/gadts-avoiding-type-constructor-escaping-scope-problems/7005/2 "2020-12-21T16:16:03Z")

</div>

Your function `send` is polymorphically recursive, which means that you need an explicit type annotation:

```ocaml

 let rec send: type input output. (input, output) key -> input -> t -> unit =
  fun key value t ->
    let map = !t in
    let handler, targets = Hmap.get key map in
    let emitter event_from_source =
      List.iter (fun (Key target) -> send target event_from_source t) targets
    in
    handler emitter value

```

After this small change, everything works as expected.

---

<div class="post-metadata">

**Author:** ![roddy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/roddy/32/2261_2.png) [@roddy](https://discuss.ocaml.org/u/roddy)\
**Post date:** [December 21, 2020, 4:20pm UTC](https://discuss.ocaml.org/t/gadts-avoiding-type-constructor-escaping-scope-problems/7005/3 "2020-12-21T16:20:03Z")

</div>

Thanks! I tried something like that but got the syntax wrong.
