-
Notifications
You must be signed in to change notification settings - Fork 75
Better Metadata
Metadata representation in core.typed is not very useful. We choose not to directly parameterise each IMeta class with an extra parameter because:
- it's inconvenient to give an extra parameter to everything
- 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}
.
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.