Fork me on GitHub
#beginners
<
2020-12-05
>
Chinmay Dalal17:12:28

can bit-xor be used as logical xor?

Chinmay Dalal17:12:08

is there something elegant then?

seancorfield18:12:14

@U01CLETCE1L It's easy enough to write your own:

user=> (defn xor [p q] (and (or p q) (not (and p q))))
#'user/xor
user=> (for [a [true false] b [true false]] (list a b (xor a b)))
((true true false) (true false true) (false true true) (false false false))
user=>
See https://en.wikipedia.org/wiki/Exclusive_or#Equivalences,_elimination,_and_introduction for the logic.

Chinmay Dalal19:12:16

(defn xor [& args]
  (odd? (count (filter true? args))))

seancorfield20:12:00

That's not quite the same semantics as the version I provided. Mine works with truthy/falsey which is more like the built-in and and or. Yours will only work with true for truthy.

seancorfield20:12:20

If you update yours to (filter identity args) it'll have truthy/falsey semantics. (mine was strictly a 2-arity version so I can see why that's not generally useful!)

Chinmay Dalal09:12:27

oh yeah i expect only true or false as input

tws14:12:28

i would use bit-xor as a guide to write your own multi-arity one

(defn bit-xor
  "Bitwise exclusive or"
  {:inline (nary-inline 'xor)
   :inline-arities >1?
   :added "1.0"}
  ([x y] (. clojure.lang.Numbers xor x y))
  ([x y & more]
    (reduce1 bit-xor (bit-xor x y) more)))

shidima21:12:54

Could some one tell me why the calculate-row function returns nil and not a number? https://pastebin.com/TJzf7pXb (Advent of Code spoiler)

phronmophobic21:12:11

it looks like a misplaced paren. moving the cond statement to the else branch of the if statement fixes "returning nil" (I didn't check logical correctness otherwise):

(defn calculate-row
  [data rows]
  (loop [d data
         r rows]
    (if (= (rest d) ())
      r
      (cond
        (= (first d) \F) (recur (rest d) (bottom r))
        (= (first d) \B) (recur (rest d) (top r))))))

phronmophobic21:12:06

I recommend the following idiom when looping using loop (which was originally recommend by someone in this slack): https://clojuredocs.org/clojure.core/loop#example-5a1de497e4b0a08026c48cc4

;; Iterating over a collection using loop

;; 1. First call (seq xs) on the given argument and then check for nil 
;; 2. Then call next/first and use these.

(loop [xs (seq [1 2 3 4 5])
       result []]
  (if xs
    (let [x (first xs)]
      (recur (next xs) (conj result (* x x))))
    result))

;; the same loop can be written using destructing,
;; but the compiler will generate two consecutive
;; seq calls and is slightly less efficient.

(loop [[x & r :as xs] (seq [])
       result []]
  (if xs
    (recur r (conj result (* x x)))
    result))

shidima21:12:44

Yes, it indeed returns the value now. thanks!

shidima21:12:48

I will keep that in mind

dpsutton21:12:16

the first if is ignored. it is executed but nothing uses its return value so it might as well never happen. you then have a cond which will return a value if the predicate is hit, but if none of those predicates match it returns nil. also, you have a loop expression but there are no recur expressions so it will never loop

dpsutton21:12:01

oh sorry. you do have recurs. but if neither condition of the cond is satisfied it returns nil