2010-05-18 16 views
6

En F #, me gustaría tener lo que veo como un tipo de dato abstracto bastante estándar:F #: ¿No se puede ocultar una abreviatura de tipo en una firma? Por qué no?

// in ADT.fsi 
module ADT 
    type my_Type 

// in ADT.fs 
module ADT 
    type my_Type = int 

En otras palabras, el código dentro del módulo sabe que my_type es un int, pero el código fuera no lo hace. Sin embargo, F # parece tener una restricción donde las abreviaturas de tipo específicamente no se pueden ocultar con una firma. Este código proporciona un error de compilación y la restricción se describe en here.

Si my_Type fue en su lugar una unión discriminada, entonces no hay error de compilación. Mi pregunta es, ¿por qué la restricción? Me parece recordar que puedo hacer esto en SML y Ocaml, y además, ¿no es una cosa bastante estándar cuando se crea un tipo de datos abstracto?

Gracias

Respuesta

10

Como señala Ganesh, esta es una limitación técnica del compilador F # (y del tiempo de ejecución .NET), porque la abreviación de tipo simplemente se reemplaza por el tipo real durante la compilación. Como resultado, si se escribe una función:

let foo (a:MyType) : MyType = a + 1 

El compilador compilará como un método .NET con la siguiente firma:

int foo(int a); 

Si el tipo real de la abreviatura estaba oculto de la usuarios de la biblioteca, entonces no podrían reconocer que la función foo está funcionando realmente con MyType (esta información probablemente se almacena en algunos metadatos específicos de F #, pero no es accesible para otros lenguajes .NET). .).

Tal vez la mejor solución para este limiation es definir el tipo como un único caso discriminado unión:

type MyType = MT of int 
let foo (MT a) = MT(a + 1) 

Trabajar con esta clase de tipo es muy conveniente. Agrega algunos gastos generales (hay nuevos objetos creados al construir un valor del tipo), pero eso no debería ser un gran problema en la mayoría de las situaciones.

+0

Sí, gracias a Tomas y Ganesh también. Ahora entiendo el problema, y ​​puedo ver que, dada esta estrategia de compilación, este problema es una consecuencia. Es un poco decepcionante ya que estoy trabajando casi por completo en el espacio F #, pero sé que la interoperabilidad es muy importante, ¡así que no me quejaré! :-) –

1

Por lo que entiendo F # no permite una abreviatura que se oculta por una firma.

Encontré esto link donde el blogger comentó sobre esto, pero no estoy seguro de los detalles de por qué este es el caso.

Mi suposición es que este es un conjunto de restricciones para permitir una interoperabilidad más efectiva con otros lenguajes en el CLR.

4

Tenga en cuenta que se puede definir un tipo de abreviatura como privada dentro de un módulo:

// File1.fs 
module File1 
    type private MyType = int 
    let e : MyType = 42 
    let f (x:MyType) = x+1 

// Program.fs 
module Program 
do printfn "%A" (File1.f File1.e) 

soy claro por qué no se puede ocultar con una firma; Logré un error para considerarlo.

+0

Es cierto, pero el sentido en el que estoy imaginando un ADT permite a los clientes saber sobre el tipo, pero no su representación. Si tengo otra función en File1, let empty(): MyType = 1 ¿Puedo llamar a esta función desde fuera de File1 y pasar su resultado a f? –

+0

Sí (he editado el ejemplo anterior). Pero veo tu punto, esto es klutzy, como p. File1.MyType no aparece como una entidad en la lista intellisense, aunque File1.MyType aparece en las firmas de f y e. – Brian

+0

Tenga en cuenta que esto no le impide hacer algo como 'File1.f 42' desde fuera del módulo, por lo que la información que' MyType = int' no está realmente oculta. Por desgracia, esto no logra el efecto deseado. – sepp2k

5

Las abreviaturas de tipo en F # se compilan lejos (es decir, el código compilado utilizará int, no MyType), por lo que no puede hacer que sean abstractas. En teoría, el compilador podría hacer cumplir la abstracción dentro del mundo F #, pero esto no sería muy útil ya que aún se filtraría en otros idiomas.

Cuestiones relacionadas