0
votes

I am learning Common Lisp using clisp and have entered following code:

(defun ordered (x y)
   (if (< x y)
       (list x y)
       (list y x)))

(setq l (ordered 28 49))
(print l)
(setq l (ordered 49 28))
(print l)

Expected these answers: (28 49) (49 28)

Got these answers: (28 49) (28 49)

In the solutions of this book I have found the same function definition. What could be wrong?

1
Welcome to Stack Overflow! The results that you're seeing make sense to me - can you please include the exercise that you're trying to complete?Cel Skeggs
I expect exactly the answer you get. That is what ordered should do, no?Svante
The exercise is to use if with an comparison clause and two result clauses, one for comparison true and one for comparison nil (false). Answer 1 is ok because 28 is less than 49. Answer 2 is not because 49 is not less than 28 which produces nil. Result clause 2 should work and produce (49 28) what never happens.klk2ptx
Now I have checked this expression in the REPL and have replaced both (list x y) and (list y x) by (print '<') and (print '>). Now I am getting expected results. It looks to me as if the list expression in the if special function were calculated only once with (list x y) and then used in both result clauses despite the values of x y. Details to this behaviour of the if special function are really appreciated. Or am I doing false assumptions?klk2ptx
When you call (ordered 49 28), x is bound to 49 and y is bound to 28. Since (< x y) is false, the result of the function is the list produced by the third argument of if (the else clause). That clause builds a list where the first element is y, 28, and the second element is x, 49. That's why the returned value is (28 49). The ordered function takes two elements and sorts them.coredump

1 Answers

4
votes

Your code

(defun

defines a function,

        ordered 

named "ordered",

                (x y)

that expects two arguments which will be known as "x" and "y" in its body, whereupon on receiving the arguments (i.e. having been called with two values, e.g. (ordered 49 28))

   (if (< x y)

it will compare them, and in case the first was smaller than the second, it will produce

       (list x y)

the same two values repackaged in a list (i.e. '(49 28)); or otherwise, if the first value was not smaller than the second,

       (list y x)))

it will produce the list containing the second value first, and then the first argument value (i.e. '(28 49)).

So, which was the case here, of comparing the 49 and 28?


Reading this code generally, we can say that if it receives the smaller number as its first argument, it will produce the smaller number first and the bigger number second, in the result list;

and in case it receives the smaller number as its second argument, it will produce the smaller number first and the bigger number second, in the result list.

Reading this back, we can see that this description can be simplified further into one simple statement: it will always produce ______ number first, and ______ second, in the resulting list.


Another way to attack this, is to write down the function created by that definition,

( lambda (x y)  (if   (< x y)    (list x y)    (list y x) ) )

Then follow its application symbolically:

(   ( lambda (x y)  (if   (< x y)    (list x y)    (list y x) ) )
    49
    28  )

==

(let  (   (x   49)
          (y   28)
      )
                    (if   (< x y)    (list x y)    (list y x) ) )

==

(let  (   (x   49)
          (y   28)
      )
                    (if   (< 49 28)  (list x y)    (list y x) ) )

==

(let  (   (x   49)
          (y   28)
      )
                    (if   FALSE      (list x y)    (list y x) ) )

==

(let  (   (x   49)
          (y   28)
      )
                                                   (list y x)   )

==

(let  (   (x   49)
          (y   28)
      )
                                                   (list 28  49) )

==

(list  28  49)