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

Reply via email to