After a lot of experimentation with types and interfaces, I have somewhat redesigned clojure.contrib.types. The new version contains some breaking changes, but the changes are minor.
There are now two different ways to define types, one of them being algebraic data types, which are now defined by defadt rather than deftype. The other change concerning algebraic types is that the first argument to defadt is the type tag (a namespace-qualified keyword) rather than a symbol from which the keyword is constructed. This is much simpler. There is still a deftype, but it now defines something more basic, which in fact I ended up using more often. In its simplest form, (deftype ::foo foo) defines a constructor function foo that simply adds {:type ::foo} metadata to its argument. It also defines print-method such that an object made with (foo x) is printed as (foo x). It is up to the client code to ensure that x is an object that can take metadata, i.e. in practice a collection. If you want more control over what goes inside your data structure, you can provide a constructor function as a third argument: (deftype ::foo foo (fn [x] {:value x})) With this definition, foo will call the provided constructor and attach the type tag to the result. (foo 42) thus yields {:value 42} with the type tag ::foo. The data representation still must be a collection, to allow metadata, but the constructor can ensure that it has specific properties, or verify that the input data satisfies some conditions. One inconvenience with the constructor approach is that object constructed as shown above now print as (foo {:value 42}) which is not the syntax of the constructor. This can be avoided by providing a deconstructor function as a fourth argument. We thus have: (deftype ::foo foo (fn [x] {:value x}) (comp list value)) The deconstructor function should return the list of arguments that needs to be given to the constructor in order to create an equivalent object. It is at the moment used only for printing, but it will be used in a future extended version of clojure.contrib.types/match as well. These basic type definition actually cover most situations in which I had used algebraic data types before. Algebraic types are needed only when multiple constructors or argument-free constructors are required. Future plans: I intend to follow Rich's advice and implement algebraic types as maps rather than vectors. Client code that does not depend on the representation should not be affected. I also intend to extend the match function to non-algebraic data types, though I won't make promises about the details yet. Konrad. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---