4

Q: is there a predicate function for dotted pairs?

In other words, is there a function that distinguishes between dotted pairs and 2-element proper lists:

(some-predicate-p '(a . b))             ; => t
(some-predicate-p '(a   b))             ; => nil

The broader context: I need to access the second element of a pair of values, and would like the function to "do the right thing" when it's fed either a dotted pair or a 2-element proper list:

(cdr  '(a . b))                           ; => b
(cadr '(a   b))                           ; => b

Since cdr and cadr cannot be dropped in interchangeably between proper and improper lists:

(cadr '(a . b))                           ; => error
(cdr  '(a   b))                           ; => (b)
  • (and (cdr x) (atom (cdr x))) FWIW, this is a duplicate of this StackOverflow question, except that here you are testing only one cons. – Drew Apr 3 '15 at 17:08
4

Here is a simple test for a dotted pair (your question):

(and (cdr x) (atom (cdr x)))

And here is a test for a dotted list (of any length):

(let ((last  (last x))) (and (cdr last) (atom (cdr last))))
3

Got it: helped along by @abo-abo's answer, the following predicate function detects dotted pairs:

(defun dotted-p (x)
  "Returns `t' if X is a dotted-pair."
  (not (consp (cdr x))))

(dotted-p '(a . b))                     ; => t
(dotted-p '(a   b))                     ; => nil
  • 2
    The only issue I could see here is that '(a . nil) be considered a dotted pair when really it just a 1 element proper list (equivilant to '(a)), If you wanted to account for this, and also for full type safety, you could use this is your function body (and (consp x) (cdr x) (not (consp (cdr x)))) – Jordon Biondo Apr 3 '15 at 14:24
  • 1
    @JordonBiondo: good point on the edge case. I think, for my specific use, I'd want to leave it as is, but the more general case should probably work as you're suggesting. – Dan Apr 3 '15 at 14:26
  • I disagree. (cons a nil) is by definition a dotted pair, even though it can also be regarded as a one-element list. But I would certainly include the (consp x) condition as suggested by @JordonBiondo. – tripleee Apr 10 '15 at 10:09
2

There isn't such a function to my knowledge, but you can use something like this:

(defun codr (x)
  (let ((y (cdr x)))
    (if (consp y)
        (car y)
      y)))

But it's better to just know what kind of data you're expecting.

  • Thanks, although this function return the same value (b) when used on either a dotted-pair or a proper list: (codr '(a b)) => b and (codr '(a . b)) => b. Still, +1 because it pointed me in the right direction. – Dan Apr 3 '15 at 13:57
  • And I agree that it's better to know the type of data to expect, but it's for end-user use and I'd like to allow people to use either version as their tastes dictate. – Dan Apr 3 '15 at 14:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.