3

I'm using the function iterate to create a lazy sequence. The sequence keeps producing new values on each item. At one point however the produced values "doesn't make sense" anymore, so they are useless. This should be the end of the lazy sequence. This is the intended behavior in a abstract form.

My approach was to let the sequence produce the values. And once detected that they are not useful anymore, the sequence would only emit nil values. Then, the sequence would be wrapped with a take-while, to make it finite.

simplified:

(take-while (comp not nil?)
   (iterate #(let [v (myfunction1 %)]
                (if (mypred? (myfunction2 v)) v nil)) start-value))

This works, but two questions arise here: Is it generally a good idea to model a finite lazy sequence with a nil as a "stopper", or are there better ways?

The second question would be related to the way I implemented the mechanism above, especially inside the iterate. The problem is: I need one function to get a value, then a predicate to test if it's valid, if yes: in needs to pass a second function, otherwise: return nil. I'm looking for a less imperative way tho achieve this, more concretely omitting the let statement. Rather something like this:

(defn pass-if-true [pred v f]
   (when (pred? v) (f v)))

#(pass-if-true mypred? (myfunction1 %) myfunction2)

For now, I'll go with this:

(comp #(when (mypred? %) (myfunction2 %)) myfunction1) 
1
  • by the way: (comp not nil?) is better as (complement nil?). Also (if (mypred? (myfunction2 v)) v nil) could be replaced by (when (mypred? (myfunction2 v)) v) Commented Feb 11, 2016 at 9:50

2 Answers 2

4

Is it generally a good idea to model a finite lazy sequence with a nil as a "stopper", or are there better ways?

nil is the idiomatic way to end a finite lazy sequence.

Regarding the second question, try writing it this way:

(def predicate (partial > 10))
(take-while predicate (iterate inc 0))
;; => (0 1 2 3 4 5 6 7 8 9)

Here inc takes the previous value and produces a next value, predicate tests whether or not a value is good. The first time predicate returns false, sequence is terminated.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer! My probem is, transfered to your example, that inc must be wrapped by another f, say e.g. str . but I can already tell that a number doesn't pass the truth-test before convertion to a string. Well, maybe I'm sort of forgetting that these seqs are lazy, so I could just wrap your whole example with a (map str ..) ... right..?
Exactly. Or just use (comp str inc) in place of inc. If you need to convert to string before checking, but don't want string in results; (comp predicate str)
0

Using a return value of nil can make a lazy sequence terminate.

For example, this code calculates the greatest common divisor of two integers:

(defn remainder-sequence [n d]
  (let [[q r] ((juxt quot rem) n d)]
    (if (= r 0) nil
        (lazy-seq (cons r (remainder-sequence d r))))))

(defn gcd [n d]
  (cond (< (Math/abs n) (Math/abs d)) (gcd d n)
        (= 0 (rem n d)) d
        :default (last (remainder-sequence n d))))

(gcd 100 32) ; returns 4

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.