2009-11-17 8 views
19

He estado haciendo algo de programación OCaml últimamente para aprender el idioma y familiarizarme más con la programación funcional. Recientemente, he empezado a pensar que me gustaría ser capaz de extender un tipo existente (ya sea integrado en, o uno de mi propia), por ejemplo:Extender un tipo existente en OCaml

type bexp = 
    And of bexp * bexp 
| Or of bexp * bexp 
| Xor of bexp * bexp 
| Not of bexp;; 

Ahora digamos que quiero añadir una variante de Nop a este tipo, pero solo para usar en un nuevo tipo, tipo de herencia. Oye, se supone que son tipos de datos algebraicos, ¿verdad? Entonces, ¿por qué no algo así como:

type nbexp = bexp | Nop nbexp ;; 

... pero esto no es válido OCaml, se da un error de sintaxis. Básicamente, lo que trato de hacer es decir que quiero que nbexp incluya todo lo que incluye bexp y también añadirle un Nop. Supongo que esto no es posible porque, si, por ejemplo, utilizaras el constructor Y no habría manera de determinar si era un tipo bexp o un tipo nbexp. (Creo que el constructor Nop tomando un nbexp también puede ser problemático.)

Entonces, ¿hay alguna manera de hacer algo como esto en OCaml? Y, ¿es este el tipo de cosa que se puede hacer en Haskell (con tipos de clases, tal vez)?

+1

quizás te interesen: https://sites.google.com/site/ocamlopen/ –

Respuesta

19

Una solución interesante es utilizar variante polimórfica:

type bexp = 
[ `And of bexp * bexp 
| `Or of bexp * bexp 
| `Xor of bexp * bexp 
| `Not of bexp ];; 

type nbexp = [ bexp | `Nop of nbexp ];; 

Tenga en cuenta que las variantes polimórficas son más difíciles que los normales, pero permitir la extensión del tipo.

Un ejemplo interesante de evaluación de la expresión, la extensión, utilizando variante polimórfica se pueden encontrar en una prueba de directorios de la fuente ocaml, consulte la Actualización svn

+1

He oído hablar de ellos, pero no han tenido tiempo de uso muy ellos. Esto me da una buena razón práctica para aprender más sobre ellos. Gracias. – aneccodeal

4

Oigan, se supone que son tipos de datos algebraicos, ¿no?

Derecha. Y algebraic data types están construidos por uniones y productos etiquetados (también conocidos como discriminados). Lo que desea es solo una unión (no etiquetada), que es no, un tipo de datos algebraico y no es compatible con Haskell. OCaml tiene variantes polimórficas (ver otras respuestas).

Typed Scheme es compatible con uniones no etiquetadas, por lo que es posible que desee comprobarlo.

4

Como usted mismo conjetura correctamente, esto no es posible en los tipos algebraicos. Estoy de acuerdo con la sugerencia de Apocalisp de que simplemente puede envolver la parte "heredada" de nbexp en un constructor propio.

Me gustaría añadir que la falta de herencia de los tipos algebraicos es parte de su maravilla. Esto significa que una expresión como And(foo, bar) está tipada de forma inequívoca, y que la conversión (ya sea hacia arriba o hacia abajo) no tiene ninguna función en el sistema de tipos. Esto produce mayor seguridad y mayor claridad. Por supuesto, requiere del programador que maneje explícitamente los casos en los que desea interactuar con las partes bexp de nbexp, pero si lo piensa así, así es como se realiza la mayor seguridad y claridad en la práctica.