2011-12-14 23 views
5

Estoy escribiendo un pequeño servicio erlang y me gustaría poner restricciones a mis tipos.Cómo usar la funcionalidad -spec en erlang

Encontré la funcionalidad -spec, y me parece que esta es una forma de 'bloquear' las firmas de funciones para tipos específicos.

Mi ejemplo sería una función como:

fib(N) when N < 3 -> 
    1; 
fib(N) -> 
    fib(N-1) + fib(N-2). 

añadiendo la línea

-spec fib_cps(pos_integer()) -> pos_integer(). 

debe asegurarse de que el método devuelve al menos el tipo correcto, pero esto no parece ser el caso. .

de Si cambio de la función a:

fib(N) when N < 3 -> 
    ok; 
fib(N) -> 
    not_ok. 

el código aún se compila, funciona bien e incluso se ejecuta.

¿Qué es lo que no entiendo?

+1

Por cierto, su especificación de tipo debería parecerse a '-spec fib_cps (pos_integer()) -> pos_integer().' (Tenga en cuenta los paréntesis vacíos), de lo contrario, Dialyzer piensa que quiere decir el átomo 'pos_integer'. – legoscia

Respuesta

11

El compilador omite esos comentarios. Pero puede usar el dializador para hacer un análisis de código estático. Esta herramienta le advertirá sobre violaciones de especificaciones.

+0

¿Eso significa que para asegurar el código "estable" debe ejecutar la herramienta de dializador en la parte superior del compilador? ¿Es así como se soluciona todo el problema de la verificación de tipos? –

+0

@MartinKristiansen Sí, si desea un código de producción estable, debe ejecutar el dializador. Tal vez no todas las construcciones, pero periódicamente. Por ejemplo, puede integrarlo con el sistema de compilación diaria, si usa uno. – werewindle

1

Como werewindle dice en another answer, -spec solo se utiliza para el análisis, no como parte de la firma. Si desea verificar los tipos de entrada, puede incluir cheques para el tipo en la guardia. Así, en su ejemplo, se puede hacer:

fib(N) when is_integer(N), N > 0, N < 3 -> 
    1; 
fib(N) when is_integer(N), N >= 3 -> 
    fib(N-1) + fib(N-2). 

O, más idiomática, ya que sólo hay dos casos base legítimos:

fib(1) -> 1; 
fib(2) -> 1; 
fib(N) when is_integer(N), N >= 3 -> 
    fib(N-1) + fib(N-2). 

Esto le impide hacer algo así como fib(bogus) o fib(0.5) o incluso fib(-1). Si lo intenta, fallará con un badmatch en tiempo de ejecución.

Nota: las únicas funciones que puede usar en un guard son funciones integradas permitidas por el tiempo de ejecución. La mayoría de ellos están en el módulo erlang.

+0

Veo, pero lo que realmente me gustaría es algún tipo de comprobación de tipo estática, como en ML. Lo que significa que me gustaría especificar un tipo A: = C | D. Y luego defina el método para tener type forinstance (_ -> A). ¿Conoces idiomas con buenos mecanismos de concurrencia que puedan hacer eso sortadamente? –

+2

@MartinKristiansen: dializador es una herramienta erlang estándar. Se envía con erlang y se debe usar en cualquier proyecto de erlang. Sí, el análisis estático no es parte del compilador, pero de todos modos puede hacer esto en cualquier momento que desee. Imagine, si el preprocesador C sería una herramienta separada del compilador. Sería de alguna manera incómodo, pero está bien. – werewindle

Cuestiones relacionadas