Marek Kubica <[email protected]> writes:
> 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?
> 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.
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. ;-)
Bye,
Tassilo
--
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