haskell - programming - Extendiendo un tipo existente en OCaml
lenguaje standard ml (4)
Últimamente he estado haciendo algo de programación en OCaml para aprender el idioma y para familiarizarme más con la programación funcional. Recientemente, comencé a pensar que me gustaría poder extender un tipo existente (ya sea integrado o propio), por ejemplo:
type bexp =
And of bexp * bexp
| Or of bexp * bexp
| Xor of bexp * bexp
| Not of bexp;;
Ahora digamos que quiero agregar una variante Nop a este tipo, pero solo para usar en un nuevo tipo, algo así como herencia. Hey, se supone que estos son tipos de datos algebraicos, ¿verdad? Entonces, ¿por qué no algo como:
type nbexp = bexp | Nop nbexp ;;
... pero esto no es válido OCaml, da un error de sintaxis. Básicamente, lo que estoy tratando de hacer es decir que quiero que nbexp incluya todo lo que bexp incluye y que también agregue un Nop a eso. Supongo que esto no es posible porque, por ejemplo, si usara el constructor And no habría manera de determinar si era un tipo bexp o un tipo nbexp. (Creo que el constructor Nop que toma 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 clases de tipos, quizás)?
Hey, se supone que estos son tipos de datos algebraicos, ¿verdad?
Derecha. Y los tipos de datos algebraicos se construyen mediante uniones y productos etiquetados (también discriminados). Lo que desea es solo una unión (no etiquetada), que no es un tipo de datos algebraico y no es compatible con Haskell. OCaml tiene variantes polimórficas (ver otras respuestas).
El esquema tipificado admite uniones no etiquetadas, por lo que es posible que desee verificarlo.
Actualización: Ocaml ahora tiene tipos extensibles. http://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec246
Aqui harias
type bexpr += Nop of bexpr
Como usted mismo conjetura correctamente, esto no es posible en tipos algebraicos. Estoy de acuerdo con la sugerencia de Apocalisp de que puede simplemente 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á tipeada de manera ambigua, y que el casting (hacia arriba o hacia abajo) no tiene ningún papel que desempeñar en el sistema de tipos. Esto proporciona tanto mayor seguridad como mayor claridad. Por supuesto, no le exige al programador que maneje explícitamente los casos en los que quiere interactuar con las partes de nbexp
de nbexp
, pero si lo piensa, así es como se realiza el aumento de la seguridad y la claridad en la práctica.
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 complicadas que las normales, pero permiten la extensión del tipo.
Un ejemplo interesante de evaluación de expresión, con extensión, utilizando una variante polimórfica se puede encontrar en los directorios de prueba de la fuente de ocaml, vea la svn