top | item 6069219

(no title)

hkolek | 12 years ago

I am familiar with this line of reasoning and I have read the Joy of Clojure. I can't say that I agree though. The article you linked is just opinion and doesn't back up its arguments at all. Afaict, it really boils down to "it's not CL" and "it's not built on cons cells". I agree that the fact that Clojure sits on top of the Java type system is a bit of a mess but it's a language to get shit done and not satisfy some purists.

> "The Joy Of Clojure" which contains 20 line of marketing slogans for 1 line of code

> but I'm not going to perform such a tedious task for free

Well, obviously there's no point in discussing this further and we have to agree to disagree. Have a nice day anyway.

discuss

order

dschiptsov|12 years ago

Let's make it simple.) There is classic homework code in two different dialects of Lisp:

  (define (cross xs ys)
      (cond ((or (null? xs) (null? ys)) '())
            ((atom? xs) (cons (list xs (car ys)) (cross xs (cdr ys))))
            (else (append (cross (car xs) ys) (cross (cdr xs) ys)))))

  (defun cross (xs ys)
      (cond ((or (null xs) (null ys)) nil)
            ((atom xs) (cons (list xs (car ys)) (cross xs (cdr ys))))
            (t (append (cross (car xs) ys) (cross (cdr xs) ys)))))
Could you, please, provide the equivalent code in Clojure?

kragen|12 years ago

Well, you could do it this way:

    (defn cross2 [xs ys]
     (cond (or (and (sequential? xs) (empty? xs)) (empty? ys)) '()
           (not (sequential? xs)) (cons (list xs (first ys)) (cross2 xs (rest ys)))
           true (concat (cross2 (first xs) ys) (cross2 (rest xs) ys))))
which is pretty much exactly homologous, allowing for the detail that you can't ask if an atom is empty? in Clojure, cond (Arc-like) takes alternating conditions and consequents rather than condition-consequent pairs, and the spellings of the list operations no longer refer to IBM 709 machine instructions. Also, it works on any kind of sequences, not just lists, with of course a punishing performance overhead on sequences whose `rest` operation is slow.

But I would argue that this interface is poorly designed, since you can say (cross2 '(a b c) '(1 2 3)) or (cross2 'a '(1 2 3)) but not (cross2 '(a b c) '1), and worse, (cross2 '(a (b c) d) '(1 2 3)) implicitly flattens the (b c) into individual items, which is probably a latent bug rather than desired behavior. So I would argue for writing it in this form instead:

    (defn sc [x ys]  ; scalar cross
          (if (empty? ys) '() 
              (cons (list x (first ys)) (sc x (rest ys)))))

    (defn cross [xs ys]
          (if (or (empty? xs) (empty? ys)) '()
              (concat (sc (first xs) ys) (cross (rest xs) ys))))
which avoids those irregularities and makes the code easier to understand by removing misleading false symmetries.

Except really, if this isn't a homework problem, I think you should write it like this in any of these three Lisps:

    (defn cross [xs ys]
          (map (fn [x] (map (fn [y] (list x y)) ys)) xs))