a tag, that uniquely identifies the type of the message;
a dynamic value.
Values are said to be "dynamic" because, while they carry information about their type at runtime, their type is lost at compilation time. To recover static type information, one must decode the value by matching with one or more expected tags.
Ideally, we would have used an extensible GADT type to define tags. This would have been both more efficient (no need to encode values into the dynamic value type) and more convenient (no need to define encoding and decoding functions), while still allowing new types of messages to be defined by the user. Unfortunately, values of extensible types (GADT or not) interact badly with Marshal.
Values are serialized and deserialized using Marshal. Be careful with variables that are captured in Closures. For instance, extensible types like exceptions can be serialized, but they cannot be matched on after they are deserialized.
The first argument is the value that could not be decoded. The second argument is the name of the type that the value was expected to have, such as "bool" or "string".
This returns a new tag with a unique internal identifier. This guarantees that messages with different tags are not mistaken for each other. Unless you register so many tags that you reach an integer overflow.
The name of the tag is used by show. Note that if you register a tag in the scheduler, workers that are already running will not know about it. They will still be able to handle those messages, but show will print an integer instead of name. Declaring tags in a worker is kind of pointless because messages with this tag will not be readable in the scheduler.