2012-08-30 13 views
5

Estoy leyendo con interés el libro en línea "learn you some erlang" y estoy probando algunos ejercicios para verificar mi comprensión.¿Por qué Dialyzer me dice que este divertido contrato tiene dominios superpuestos?

Hice algunas modificaciones en el ejemplo FIFO, en el capítulo especificaciones de tipo y Erlang, tratando de definir un "typed_fifo (T)" (FIFO, donde todos los elementos deben ser del mismo tipo T)

mi especificación de tipo son:

-type typed_empty_fifo() :: {fifo, [], []}.

-type typed_nonempty_fifo(A) :: {fifo, nonempty_list(A), list(A)} | {fifo, [],nonempty_list(A) }.

-type typed_fifo(A) :: typed_empty_fifo() | typed_nonempty_fifo(A).

y cuando lo uso en la función siguiente especificación:

-spec empty (typed_empty_fifo()) -> true;

(typed_nonempty_fifo(_)) -> false. 

empty({fifo, [], []}) -> true;

empty({fifo, A, B}) when is_list(A), is_list(B) -> false.

de Diálisis r dice que ignorará la especificación debido a la superposición del dominio.

¿Alguien puede decirme dónde cometo un error?

Tengo otro punto, antes de tratar de definir mecanografiado fifo Tenía una versión que funcionó bien, Un Dialyzer me muestra que nada impide el uso de listas incorrectas. Sorprendentemente, no encuentro una manera simple (que pueda usar en un guardia) para probar el carácter apropiado/incorrecto de una lista.

Es realmente extraño, porque cuando uso el bif length/1, ¡puede fallar con el motivo badarg!

23> L=[1,2|3]. ==> [1,2|3]

24> is_list(L). ==> true

25> length(L). ==> exception error: bad argument

in function length/1 

    called as length([1,2|3]) 

Gracias

Respuesta

3

No hay nada de malo con sus tipos y especificaciones. El problema es que el tipo de datos que se usa en Dialyzer para la representación de tipos no conserva la precisión que usted proporciona. Específicamente, la unión: {fifo, nonempty_list(A), list(A)} | {fifo, [],nonempty_list(A) } se "aplasta" en {fifo, list(A), list(A)}, ya que las tuplas tienen la misma aridad (3) y el primer elemento atómico (fifo). Dialyzer generalmente hace sobreestimaciones (como también puede ver here) para hacer que el análisis de tipo sea más eficiente. Puede ignorar esta advertencia de forma segura.

Para su segunda pregunta, is_list/1 solo comprueba si el primer constructor del término que se pasa como su argumento es una celda de cons. Incluso is_list([1|2]) devuelve true.

Si desea asegurarse de que un argumento es una lista adecuada se puede utilizar una función personalizada en una expresión case así:

case is_proper_list(L) of 
    true -> ...; 
    false -> ... 
end 

is_proper_list([]) -> true; 
is_proper_list([_|L]) -> is_proper_list(L); 
is_proper_list(_) -> false. 

Esto no se puede colocar en un guardia sin embargo. En guardias puedes usar el que sugieres en tu comentario a continuación (length(L) >= 0).

+0

Gracias Aronis. Creo que estoy pidiendo más de lo que Dialyzer tiene la intención de proporcionar. Estoy tratando de descubrir cuál podría ser el beneficio de usar esas definiciones de especificaciones, lo que el dializador puede hacer y cuál es el esfuerzo para mí. Al menos descubro este problema con una lista incorrecta. Por cierto, todavía estoy buscando una solución a mi segunda pregunta. Tengo que probar que una prueba en fun guard como: is_list (X) y también length (X)> -1 funciona. Pero se bloquea dentro de una función. – Pascal

+0

He editado la respuesta con una posible solución. Ah, y mi primer nombre es Stavros! :-) – aronisstav

0

En cuanto a su segunda pregunta, la manera correcta de trabajar con list es:

1> L = [1,2|[3]]. 
[1,2,3] 
2> is_list(L). 
true 
3> length(L). 
3 

Nota, que [Head|Tail] notación requiere de usted Tail seas list (no int) .

+0

Gracias por su respuesta. Lo sabía, pero escribí al final de la pregunta tal vez demasiado rápido. Hice esta tarea a propósito, para crear una lista incorrecta.El hecho es que mi módulo fifo creará solo fifo válida, pero nada impide que otro módulo cree una fifo incorporada en la lista incorrecta, y me gustaría comprobarlo (por el bien del ejercicio, por supuesto, en la vida real uso el sdlib one ...) – Pascal

Cuestiones relacionadas