pondermatic
pondermatic

Reputation: 6583

A list specification with more than one defined element

I have parsed a json list and it comes out with each element like:

{struct,
 [
  {<<"name">>, "<<a name>>"},
  {<<"id">>, "<<an id>>""}
 ]
}

I would like to specify this as a type, but I get an error with the following, presumably because I'm using two elements in the list definition:

-type user_data() :: {struct, [{Name_key::Binary, Name_value::Binary},{ID_key::Binary, ID_value::Binary}]}.

Is there any way to do what I'm trying to do?

Upvotes: 2

Views: 221

Answers (3)

I GIVE CRAP ANSWERS
I GIVE CRAP ANSWERS

Reputation: 18879

In most type systems, a list like [A, B] is regarded as monomorphic in the sense that A and B must have the same type. This is the case for Erlangs dialyzer type system as well. to make it possible to represent this as distinct types, the representation needs to be a product of types, formed with a tuple, {A, B} which implicitly also says that there are always precisely two elements, namely A and B and they always occur together.

There are type systems which allow you to have polymorphic lists however. One way is to encode elements as existential types. Imagine that elements A and B are "packed" in a way such that their internal representation is opaque to you and the only way you can manipulate them is through some predetermined functions, specified by the pack. Another way is to use advanced type systems, usually with dependent types, where your type is determined by the structure of the list.

Upvotes: 0

aronisstav
aronisstav

Reputation: 7914

As you are pointing out, when you are specifying the types of elements in lists only one type can be provided. Additional types can be added using the union syntax, but internally this will not retain information about the order of the elements in the list.

So your best bet is something like:

-type user_data :: {struct, [{Key::binary(), Value::binary()}]}.

You can also try:

-type      field() :: {Key::binary(), Value::binary()}.
-type name_field() :: field(). % Key is <<name>>
-type   id_field() :: field(). % Key is <<id>>
-type     fields() :: [name_field() | id_field()].
-type  user_data() :: {struct, fields()}.

This latter example retains all the information and you can extend it in a sensible manner.

Upvotes: 1

Alexey Romanov
Alexey Romanov

Reputation: 170745

You can do

-type user_data() :: {struct, [{Name_key::binary(), Name_value::binary()}|{ID_key::binary(), ID_value::binary()}]}.

meaning a list every element of which is either a {Name_key::binary(), Name_value::binary()} or an {ID_key::binary(), ID_value::binary()}. This isn't quite what you want but may be good enough.

Upvotes: 2

Related Questions