3

In this answer, the suggested way of "attaching" meta information to types was using a record:

type _foo = ... 
and foo = {n:_foo; m:meta}

but what if I have multiple types I'd like to wrap with meta information? Apparently all field names in record types must have different names, and writing:

type _foo = ... 
and foo = {n:_foo; m:meta}
...
type _fooX = ... 
and fooX = {nX:_fooX; mX:meta}

seems redundant :/. Classes are the only way to solve this? I'd like to avoid dealing with classes, if possible.

Community
  • 1
  • 1
pbp
  • 1,461
  • 17
  • 28

2 Answers2

5

You can use parameterized type, perhaps.

type 'a wrapped = { base: 'a; extra: meta }
Jeffrey Scofield
  • 65,646
  • 2
  • 72
  • 108
  • and if my types are recursive? – pbp Jan 22 '12 at 17:30
  • It's hard to say without a concrete example of what you might want. The `wrapped` type above will wrap any type, whether it's recursive or not. If you want recursion between the type `'a` and the `meta` type, you might need another type parameter. Maybe you would want `meta` itself to be a parameterized type? Try to keep it simple! – Jeffrey Scofield Jan 22 '12 at 17:35
  • for example: `type exp = BinOp exp * op * exp | Const of int` and I want the subexpressions to be wrapped with `meta` too. – pbp Jan 22 '12 at 17:42
  • If you want to annotate all the nodes of the tree by a type that can vary, you might have to design the nodes with annotation in mind I guess. So then instead of wrapper that adds annotation to a type (as above), you'd have a node type that can be parameterized by an annotation. Instead of `exp` you'd have `'a exp`. I don't think there's an automatic way to add this parametization to an existing type (happy to be proved wrong). – Jeffrey Scofield Jan 22 '12 at 17:58
3

Jeffrey's solution is correct and scales perfectly to recursive types.

type location
type 'a loc = { a : 'a; loc : location }

type exp = Int of int | Add of exp loc * exp loc

It is still possible to use the previous two-time definition of your type, as follows:

type exp_data = Int of int | Add of exp * exp
and exp = exp_data loc

Finally, a slightly different style is to use "open recursion", that is to define only an "derecursified type" open_exp with free parameters instead of recursive occurences. You can then get the recursive type back by taking the fixpoint; you can take different fixpoint, one with no additional information, and one with location interleaved for example. This is a generic construction to insert information at recursion sites, and its term-level counterpart allows for weaving different things in a recursive function (memoization, profiling, debug, etc.).

type 'e open_exp = Int | Add of 'e * 'e
type simple_exp = Simple of simple_exp open_exp
type located_exp = Loc of located_exp loc open_exp
gasche
  • 31,259
  • 3
  • 78
  • 100