Monday, December 16, 2013

difference between rest and next


(def x (next (random-ints 50)))
; realizing random number (evaluating first element)
; realizing random number (evaluating second element, which is the head of the tail)

(def x (rest (random-ints 50)))
; realizing random number

NOTE: ‘next’ tries to evaluate the head of the tail, while ‘rest’ does not, which is lazier than ‘next’

head retention

if you hold a reference to the head of a sequence, you prevent VM from GC any elements in the sequence.
e.g.
(let [[t d] (split-with #(< % 12) (range 1e8))]  [(count d) (count t)])
- because, when counting d, t is retained, and none of the elements are GC-able.
However, in
(let [[t d] (split-with #(< % 12) (range 1e8))] [(count t) (count d)])

- because after counting t, when you count d, numbers(elements) are are already counted can be GC collected.

the difference between get and find

‘find’ returns the entry of a map
‘get’ returns the value of a map
NOTE: get can be tricky when working with ‘nil’, as
(get {:ethel nil} :lucy)
;= nil
(get {:ethel nil} :ethel)
;= nil

in this case, ‘find’ is a better choice
(find {:ethel nil} :lucy)
;= nil
(find {:ethel nil} :ethel)
;= [:ethel nil]

be careful of contains?


contains works with keys not values!
(contains? [1 2 3] 0) ⇒ true !!!!
(contains? [1 2 9] 3) ⇒ false!!!!

difference between get and nth

1. get is more general, nth works with numerical collections only, like lists, sequence, array
2. whereas nth throws an IndexOutOfBoundException, get returns nil.
3. get can be used work with unsupported object types, nth does not allow this. e.g.
(get 42 0)
;= nil
(nth 42 0)
;= java.lang.UnsupportedOperationException: nth not supported on this type: Long

The same is that they treat ‘default’ value retrieval the same way
(nth [:a :b :c] -1 :not-found)
;= :not-found
(get [:a :b :c] -1 :not-found)
;= :not-found

-> and ->>

-> : thread-first macro
it puts the first argument as (always) the 1st parameter of later forms/functions. e.g.
(first (.split (.replace (.toUpperCase "a b c d") "A" "X")  " "))
;; ⇒ "X"

;; Perhaps easier to read:
(-> "a b c d"
          .toUpperCase
          (.replace "A" "X")
          (.split " ")
          first)
;; ⇒ "X"

->> : thread-last macro
it puts the first argument as (always) the last parameter of later forms/functions. e.g.
user=> (reduce +
              (take 10
                    (filter even?
                            (map #(* % %)
                                 (range)))))
;; ⇒ 1140

(->> (range)
           (map #(* % %))
           (filter even?)
           (take 10)
           (reduce +))
;; ⇒ 1140

Sunday, December 8, 2013

Using lazy-seq

the documentation of lazy-seq says:

(lazy-seq & body)
Takes a body of expressions that returns an ISeq or nil, and yields
a Seqable object that will invoke the body only the first time seq
is called, and will cache the result and return it on all subsequent
seq calls. See also - realized?

To illustrate in an example below to calculate the Fibonacci series. We utilize this lazy-seq function.

(defn fibs2_sq [a b] (cons a (lazy-seq (fibs2_impl b (+ a b)))))
(fibs2_sq 0 1)

The output is something like (assuming you run (set! *print-length* 10) to limit the length of values being printed):
(0 1 1 2 3 5 8 13 21 34 55 89 ...)

This look normal, but what if we remove the invocation of lazy-seq function, and run below code:

(defn fibs_sq [a b] (cons a (fibs_sq b (+ a b))))
(take 10 (fibs_sq 0 1))

You will first hit an error saying:
ArithmeticException integer overflow  clojure.lang.Numbers.throwIntOverflow (Numbers.java:1388)

After change the second expression to
(take 10 (fibs_sq 0N 1N))

You still hit below error:
StackOverflowError   java.math.BigInteger.add (BigInteger.java:1048)

The implication is that lazy-seq only runs the code it wraps when needed. Otherwise, you run into an infinite loop, trying to produce an infinite sequence.