code: func walk(at *AttributeDefinition, walker func(*AttributeDefinition) error, seen map[string]bool) error {
  	if err := walker(at); err != nil {
  		return err
  	}
  	walkUt := func(ut *UserTypeDefinition) error {
  		if _, ok := seen[ut.TypeName]; ok {
  			return nil
  		}
  		seen[ut.TypeName] = true
  		return walk(ut.AttributeDefinition, walker, seen)
  	}
  	switch actual := at.Type.(type) {
  	case Primitive:
  		return nil
  	case *Array:
  		return walk(actual.ElemType, walker, seen)
  	case *Hash:
  		if err := walk(actual.KeyType, walker, seen); err != nil {
  			return err
  		}
  		return walk(actual.ElemType, walker, seen)
  	case Object:
  		for _, cat := range actual {
  			if err := walk(cat, walker, seen); err != nil {
  				return err
  			}
  		}
  	case *UserTypeDefinition:
  		return walkUt(actual)
  	case *MediaTypeDefinition:
  		return walkUt(actual.UserTypeDefinition)
  	default:
  		panic("unknown attribute type") // bug
  	}
  	return nil
  }
docs: // Recursive implementation of the Walk methods. Takes care of avoiding infinite recursions by
  // keeping track of types that have already been walked.