Skip to content
frenchy64 edited this page Apr 25, 2013 · 1 revision

Problem

Metadata representation in core.typed is not very useful. We choose not to directly parameterise each IMeta class with an extra parameter because:

  1. it's inconvenient to give an extra parameter to everything
  2. it's not clear how to "update" this information".

The type of with-meta demonstrates problem no. 2.

(ann ^:nocheck with-meta 
  (All [ [x :< IObj] [y :< (Option (IPM Any Any))] ] 
    [x y -> (I x (IMeta y))]))

This uses the experimental general intersection type.

It's apparent that the metadata cannot be "updated" this way when x is instantiated to a type that already has metadata. You end up with types like (I (I Symbol (IMeta '{:a Symbol})) '{:a Number :b Number}), which isn't what we want: the metadata here is (I '{:a Symbol} '{:a Number :b Number}) where we probably want '{:a Number :b Number}.

Solution

Have a special Meta type constructor that has an IObj first argument and, when used recursively, prefers types on the outside.

with-meta becomes:

(ann ^:nocheck with-meta 
  (All [ [x :< IObj] [y :< (Option (IPM Any Any))] ] 
    [x y -> (Meta x y))]))

Now (Meta (Meta x y) z) unambiguously simplifies to (Meta x z), and the y metadata is effectively thrown away.

Clone this wiki locally