Hi, Wow, thanks for all that input :) It is always a pleasure to post on this list, to get such good advice.
On Wed, 21 Dec 2011 09:51:31 +0100 Tassilo Horn <[email protected]> wrote: > > I am idly thinging on how to create types with special restraints on > > them, like being only in the range 1-1000 or only even numbers etc > > and all normal operations like + and - still being valid. > > + and - would have wrap-around semantics, I guess? No, they wouldn't, they should error out. Actually this started as a discussion during lunch between me and a Ada proponent where such types seem to be common. I was thinking how much I can custom-tailor types, like only-odd-numbers, only-prime-numbers. As some kind of universal precondition system. Sorry if I am explaining the idea so fuzzy, I don't seem to be good in explaining. > > Anyone has an idea how to implement that? In Python I'd subclass the > > number type and implement all oparators, but how would one do this > > in Clojure? > > You could do something similar with a protocol defining the restricted > operations and a record for the numbers that implement that protocol. > > --8<---------------cut here---------------start------------->8--- > (defprotocol RestrictedArithmetics > (canonic [this]) > (r+ [this o]) > (r- [this o])) > > (defrecord RangeNum [v l u] > RestrictedArithmetics > (canonic [this] > (cond > (> v u) (RangeNum. (mod v u) l u) > (< v l) (RangeNum. (+ u v) l u) > :else this)) > (r+ [this o] > (canonic (RangeNum. (+ v (:v o)) l u))) > (r- [this o] > (canonic (RangeNum. (- v (:v o)) l u)))) > > (r+ (RangeNum. 500 1 1000) (RangeNum. 500 1 1000)) > ;=> #user.RangeNum{:v 1000, :l 1, :u 1000} > (r+ (RangeNum. 501 1 1000) (RangeNum. 500 1 1000)) > ;=> #user.RangeNum{:v 1, :l 1, :u 1000} > (r- (RangeNum. 500 1 1000) (RangeNum. 500 1 1000)) > ;=> #user.RangeNum{:v 1000, :l 1, :u 1000} > --8<---------------cut here---------------end--------------->8--- > > But I'm not quite sure, if that's a decent approach. For any > RangeNum, you have a map plus three long values, so you multiply the > memory requirements quite a bit. This is not really a problem, since first it doesn't have to wrap around, and second I don't mind a performance hit for this. In this case I happyily sacrifice performance for correctness. > > So maybe you should use `deftype' above instead of `defrecord'. > > --8<---------------cut here---------------start------------->8--- > (defprotocol RestrictedArithmetics > (canonic [this]) > (value [this]) > (r+ [this o]) > (r- [this o])) > > (deftype RangeNum [v l u] > RestrictedArithmetics > (canonic [this] > (cond > (> v u) (RangeNum. (mod v u) l u) > (< v l) (RangeNum. (+ u v) l u) > :else this)) > (value [this] v) > (r+ [this o] > (canonic (RangeNum. (+ v (value o)) l u))) > (r- [this o] > (canonic (RangeNum. (- v (value o)) l u)))) > > (value (r+ (RangeNum. 500 1 1000) (RangeNum. 500 1 1000))) > ;=> 1000 > (value (r+ (RangeNum. 500 1 1000) (RangeNum. 501 1 1000))) > ;=> 1 > (value (r- (RangeNum. 500 1 1000) (RangeNum. 501 1 1000))) > ;=> 999 > --8<---------------cut here---------------end--------------->8--- > > And maybe you should take a completely different approach. ;-) Yeah, the problem that I see is that I have an additional set of operators, r+, r- and friends, so every consumer has to be aware of my numbers and use the proper operations, like the float-operators in OCaml +. -. or the BigInteger stuff in Java. I'd like to avoid that, for my new numbers to play with the other kids :) regards, Marek -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to [email protected] Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/clojure?hl=en
