English 中文(简体)
Extending an existing type in OCaml
原标题:

I ve been doing some OCaml programming lately to learn the language and to get more acquainted with functional programming. Recently, I ve started to think that I d like to be able to extend an existing type (either built in-or one of my own), for example:

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

Now let s say I want to add a Nop variant to this type, but only for use in a new type - kind of like inheritance. Hey, these are supposed to be Algebraic data types, right? So why not something like:

type nbexp = bexp | Nop nbexp ;;

...but this isn t valid OCaml, it gives a syntax error. Basically, what I m trying to do is say that I want nbexp to include everything bexp includes and also add a Nop to that. I suppose this isn t possible because, if for example you used the And constructor there would be no way to determine if it was a bexp type or a nbexp type. ( I think the constructor Nop taking a nbexp may also be problematic.)

So is there any way to do something like this in OCaml? And, is this the sort of thing that s doable in Haskell (with typeclasses, perhaps)?

最佳回答

An interesting solution is to use polymorphic variant:

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

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

Note that polymorphic variants are trickier than normal ones, but allow extension of type.

An interesting example of expression evaluation, with extension, using polymorphic variant can be found in a test directories of the ocaml source, see the svn

问题回答

As you yourself correctly surmise, this is not possible in algebraic types. I agree with Apocalisp s suggestion that you may simply wrap the "inherited" part of nbexp in a constructor of its own.

I would add that the lack of inheritance of algebraic types is part of their wonderfulness. This means that an expression such as And(foo, bar) is umambiguously typed, and that casting (either up or down) has no role to play in the type system. This yields both greater safety and greater clarity. It does of course require of the programmer that s/he explicitly handle the cases where s/he wants to interact with the bexp parts of nbexp, but if you think about it, that s how the increased safety and clarity is realised in practice.

Hey, these are supposed to be Algebraic data types, right?

Right. And algebraic data types are constructed by tagged (aka discriminated) unions and products. What you want is just a (non-tagged) union, which is not an algebraic data type and isn t supported by Haskell. OCaml has polymorphic variants (see other answers).

Typed Scheme does support non-tagged unions, so you may want to check it out.

Update: Ocaml now has extensible types. http://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec246

Here you would do

type bexpr += Nop of bexpr




相关问题
ocamlc, module compilation

I wrote an app in ocaml. It consist of several modules: Util (util.ml) Work1 (work1.ml) -- open Util Work2 (work2.ml) -- open Util, too Main (main.ml) -- open all of them. When i compile its, using ...

How can I simplify this ocaml pattern-matching code?

I m writing a simple little ocaml program that reads an algebraic statement in from a file, parses it into an AST using ocamllex/ocamlyacc, reduces it, and then prints it. The part where I m reducing ...

How can I create a type with multiple parameters in OCaml?

I m trying to create a type that has multiple type parameters. I know how to make a type with one parameter: type a foo = a * int But I need to have two parameters, so that I can parameterize the ...

Hashtable indexed on several fields

I m currently programming an OCaml module defining a type corresponding to a CPU register. The interface of this module is the following : (* * Defines a type which represents a R3000 register. *) ...

Extending an existing type in OCaml

I ve been doing some OCaml programming lately to learn the language and to get more acquainted with functional programming. Recently, I ve started to think that I d like to be able to extend an ...

Ocaml Syntax Error

What s wrong with this code? I can t figure it out: let parent (rules : grammar) (symbol1 : string) (symbol2 : string) : (SymbolSet.t) = try SymbolSet.singleton (getParent [symbol1; symbol2] ...

热门标签