Error formatting macro: pagetree: java.lang.NullPointerException
Skip to end of metadata
Go to start of metadata
You are viewing an old version of this page. View the current version. Compare with Current  |   View Page History

A lot of things are 'rangeable'. Anything that has a logical 'next' to it can be a range. Since you can get an integer from a character by calling int on it, that applies to them as well. Thus, I wrote a char-range function that was promptly (and understandably) denied:

Stu makes some good points here:

  • Performance. I'm not all that great with squeezing every ounce of performance out of things, thus my char-range function is probably the best you'll get from me. I don't know the real performance implications.
  • If many things can be rangeable, they should probably be polymorphic.
  • Are there things that might need to be rangeable in more than one way?

I have some design ideas on of my own, mostly char-range specific:

  • Should char-range's upper bound be exclusive? How intuitive and easy would that be to work with? It would mean that, to get the lower-case alphabet, you'd have to do (char-range \a \\\{) rather than (char-range \a \z). That is awkward and unreadable. Ultimately, it's a difficult decision to make between consistency and usability.
  • char-range should be as flexible as possible. The priority should be on ultimately flexibility and not how easy it is to get a range of lower-case and upper-case letters.

Sorry for the first example's curly bracket not coming out right. It appears to be impossible to escape it and show a backslash in this markup language. If somebody else can manage it, please do so.

My implementation is of a very Haskell-like range. In Haskell, to get a string of the lower-case and upper-case alphabet, you'd use two ranges.

Prelude> ['a'..'z'] ++ ['A'..'Z']

And following that, my implementation was this:

(defn char-range
  "Returns a lazy seq of chars from start to end
  (inclusive), by step, where start defaults to Character/MIN_VALUE,
  step to 1, and end to Character/MAX_VALUE."
  ([] (char-range (Character/MIN_VALUE) (Character/MAX_VALUE) 1))
  ([end] (char-range (Character/MIN_VALUE) end 1))
  ([start end] (char-range start end 1))
  ([start end step]
     (map char (range (int start) (inc (int end)) step))))

The above Haskell example translated to Clojure using char-range:

user=> (concat (char-range \a \z) (char-range \A \Z))
(\a \b \c \d \e \f \g \h \i \j \k \l \m \n \o \p \q \r \s \t \u \v \w \x \y \z \A \B \C \D \E \F \G \H \I \J \K \L \M \N \O \P \Q \R \S \T \U \V \W \X \Y \Z)

I did a little research into Ruby's ranges, and they appear to be extremely flexible (too flexible?) polymorphic ranges. Documentation is here: