Skip to content

Instantly share code, notes, and snippets.

@namoopsoo
Last active April 6, 2019 16:51
Show Gist options
  • Save namoopsoo/607f29e923ceaba890588e69293413cf to your computer and use it in GitHub Desktop.
Save namoopsoo/607f29e923ceaba890588e69293413cf to your computer and use it in GitHub Desktop.
clojure tips

quick note on imports

  • i originally inferred this
(ns blah-namespace
  (:use clojure.core.blah )  ; this would take all the terms in blah and put them into the current namespace

  (:refer-clojure :exclude [blarg flarg]) ; but this is supposed to be a way to avoid term clash
                                          ; so blarg and flarg will not be used. (not that they are in clojure.core however)
  )

hash-maps

  • Many ways to make a hash-map,

    ; These are both fine
    boot.user=> {:name "Steve" :age 24 :salary 7886 :company "Acme"}
    {:name "Steve", :age 24, :salary 7886, :company "Acme"}
    boot.user=> {:name "Steve", :age 24, :salary 7886, :company "Acme"}
    {:name "Steve", :age 24, :salary 7886, :company "Acme"}
    
  • how to get a value from the hash-map...

    boot.user=> (steve "age")  ; no
    nil
    boot.user=> (steve 24) ; no. not even sure what this is trying to do
    nil
    boot.user=> (steve :company) ; yes
    "Acme"
    boot.user=> (steve :name) ; yes
    "Steve"
    
  • what is insane is that this is also legal... and I see this one used more often:

    boot.user=> (:name steve)
    "Steve"
    
  • and get too..

    boot.user=> (get steve :company)
    "Acme"
    
  • accessing nested hashes...

    app.core=> (get-in {:foo {:and "yes" :here "no"}} [:foo :here])
    "no"

Array things

  • similarly can index arrays like hash-maps...

      boot.user=> (def a1 [1 2 3 4])
      #'boot.user/a1
      boot.user=> a1
      [1 2 3 4]
      boot.user=> (first a1)
      1
    

Boot-repl

  • According to https://github.com/boot-clj/boot , you can set environmental variables ...

    boot.user=> (set-env! 
         #_=>   :resource-paths #{"src"}
         #_=>   :dependencies '[[me.raynes/conch "0.8.0"]])
    
  • but this is not working for me or at least not for the REPL i'm in,

    boot.user=> (:development env)
    nil
    boot.user=> (set-env!
           #_=> :development true)
    nil
    boot.user=> 
    
    boot.user=> (:development env)
    nil
    
  • And to look at one or more of what is in env

    boot.user=> (use '[environ.core :as env])
    nil
    
    ; now you can look at anything with 
    boot.user=> (env :term)
    "xterm-256color"
    
    • and clojure re-writes envrironmental variables, changing CAPITAL_LETTERS into capital-letters,
    • so if on shell one did export CAPITAL_LETTERS=bingo
    • Then environ.core could get this with (env :capital-letters)

lambda functions in clojure ( aka anonymous functions)

  • the #(...)

    boot.user=> (#(+ %1 5) 2)
    7
    boot.user=> (#(+ %1 5) 2 3)
    
    clojure.lang.ArityException: Wrong number of args (2) passed to: user/eval5691/fn--5692
    boot.user=> (#(+ %1 5 %2) 2 3)
    10
    
  • actually, another nicer looking lambda form. I like this more..

    boot.user=> (map (fn [x] (x :name)) [{:name "Jo"},{:name "Jane"},{:hmm "Yea"}])
    ("Jo" "Jane" nil)
    boot.user=> 
    
  • anonymous func approach to collecting keys from hash...

    app.core=> ((fn [{:keys [status error]}] (println status error)) {:status 400 :error false})
    400 false
    nil

Another note on conj and hashes...

  • conj hashes,
app.core=> (def blah {"acc" "123"})
#'app.core/blah
app.core=> blah
{"acc" "123"}

app.core=> (conj blah {"secret" "455"})
{"acc" "123", "secret" "455"}
app.core=> (conj blah {"secret" "455" "client_id" "5667"})
{"acc" "123", "secret" "455", "client_id" "5667"}

a weird way of calling a func using apply, and some strange dereferencing thing ,

  • Best quote about apply i read is ...

    apply is used to apply an operator to its operands.

  • so apply takes a func as its first arg and then throws whatever is next , 1 or more args, to func.

  • I Guess that's a lie, because the thing is though, you want to give func a list thing.

    boot.user=> (max 1 2 3 4 )
    4
    boot.user=> (apply #(+  %1 %3) '[4 5 6 ])
    10
    
  • but all of these forms seem to work which is weird

    boot.user=> (apply #(+  %1 %3) [4 5 6] )
    10
    boot.user=> (apply #(+  %1 %3) `[4 5 6] )
    10
    boot.user=> (apply #(+  %1 %3) '[4 5 6] )
    10
    
    
    

importing from other files...

  • for a file "src/lesson_two/dynamo.clj" , use will let the namespace in it referred to as db

    boot.user=> (load-file "src/lesson_two/dynamo.clj")
    #'lesson-two.dynamo/get-prime
    boot.user=> (use '[lesson-two.dynamo :as db])
    nil
    

Reload mechanism...

  • reload after making changes if using use

    (use 'your.namespace :reload)
  • When using a lein repl, the above was not working for some reason, but this pattern worked for me...

    • pull up a REPL..

      app.core=> (require '[app.core :as mycore])
      
      app.core=> (mycore/blah "hi")
    • edit code ...

    • then in the REPL...

      app.core=> (require '[app.core] :reload)
      nil
      
      app.core=> (mycore/blah "hi")
    • and mycore/blah is available after the reload with any changes taking effect.

    • but also this was also good , reload-all ... not sure about the difference definitively

      (require 'app.core :reload-all)
  • Also, for the namespace the repl itself is in, this worked to reload that..

    (use 'app.core :reload-all)

interesting way of checking types in a hash map

  • throw error if wrong type

    boot.user=> (def steve {:name "Steve", :age 24, :salary 7886, :company "Acme"})
    #'boot.user/steve
    boot.user=> 
    
    boot.user=> steve
    {:name "Steve", :age 24, :salary 7886, :company "Acme"}
    boot.user=> 
    
    boot.user=> (-> steve :age num)
    24
    boot.user=> (-> steve :company num)
    
    java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
    
    boot.user=> (-> steve :company str)
    "Acme"
    
    

string splitting

  • requires an import

    boot.user=> (use '[clojure.string :only (split triml)])
    nil
    boot.user=> (split "blarmey ; klarg ; jlarf ; mlarg" #";")
    ["blarmey " " klarg " " jlarf " " mlarg"]
    
  • and trimming white space and beginning, end of a string,

    boot.user=> (clojure.string/trim " a sdfd ")
    "a sdfd"
    

Exception handling

  • casting exception

    boot.user=> steve
    {:name "Steve", :age 24, :salary 7886, :company "Acme"}
    boot.user=> (try (-> steve :company num) (catch java.lang.ClassCastException ex "nope"))
    "nope"
    
  • useful technique for capturing problems with the NullPointerException. Sometimes I will get one without explanation...

  • from, https://stackoverflow.com/questions/10529063/getting-clojure-stacktrace

  • using ... clojure.repl.pst

user=> (try (/ 1 0) (catch Exception e (pst e)))
ArithmeticException Divide by zero
    clojure.lang.Numbers.divide (Numbers.java:156)
    clojure.lang.Numbers.divide (Numbers.java:3691)
    user/eval28 (NO_SOURCE_FILE:8)
    clojure.lang.Compiler.eval (Compiler.java:6511)
    clojure.lang.Compiler.eval (Compiler.java:6477)
    clojure.core/eval (core.clj:2797)
    clojure.main/repl/read-eval-print--6569 (main.clj:245)
    clojure.main/repl/fn--6574 (main.clj:266)
    clojure.main/repl (main.clj:266)
    clojure.main/repl-opt (main.clj:332)
    clojure.main/main (main.clj:427)
    clojure.lang.Var.invoke (Var.java:423)

Another Exception handling and or tracing technique,

  • using org.clojure/tools.trace
user=> (dotrace [list?]
  #_=> (do
  #_=>  (list? [])
  #_=>  (list? '(1 2 3))
  #_=>  (list?)
  #_=>  (list? (defn f [] (do ())))
  #_=>  (list? "a"))
  #_=> )
IllegalStateException Can't dynamically bind non-dynamic var: clojure.core/list?
  clojure.lang.Var.pushThreadBindings (Var.java:353)
  • ,
user=> (dotrace [list?]
  #_=>   (do
  #_=>   (list? [])
  #_=>   (list? '(1 2 3))
  #_=>   (list?)
  #_=>   (list? (defn f [] (do ())))
  #_=>   (list? "a")))
TRACE t1216: (list? [])
TRACE t1216: => false
TRACE t1217: (list? (1 2 3))
TRACE t1217: => true
TRACE t1218: (list?)
ArityException Wrong number of args (0) passed to: core$list-QMARK-  
  clojure.lang.AFn.throwArity (AFn.java:437)

The arrow ->

  • this example says it all.

    (def c 5)
    ;; => #'user/c
    
    (-> c (+ 3) (/ 2) (- 1))                          
    ;; => 3
    
    ;; and if you are curious why
    (use 'clojure.walk)
    ;; => nil
    
    (macroexpand-all '(-> c (+ 3) (/ 2) (- 1)))
    ;; => (- (/ (+ c 3) 2) 1)
  • The ->> is also used. Have not yet differentiated between the two.

vectors and lists

  • with a vector, like ["a" "b" "c"], you can index, like

    boot.user=> (["a" "b" "c"] 1)
    "b"
    
  • but apparently, vectors are difficult to modify.

  • Whereas , a list '(1 2 3) can have easier appending, but it is harder to index. nth on a list will be a O(n) operation as opposed to O(1) on a vector.

    (nth (list 1 2 3 4 5) 3)
    
  • reference: http://stackoverflow.com/a/11505188/472876

  • Also..

    "Lists logically grow at the head, while vectors logically grow on the tail. You can see this in action when using the conj function. It will grow the collection according to the type of collection given to it. While you can grow collections on either side, it is performant to do so in this way."

group by , wow this is cool

frequencies is like the pythonic collections.Counter

  • Get counts nicely.

nice way to extract partial hash map , based on keys

  • using something that reminds me of perl for some reason,

    boot.user=> (def h {:time-length 15N, :core-category "work", :project-identifier "proj-1", :sub-category "code"} ) 
    boot.user=> ( #(select-keys % [:core-category :project-identifier]) h)
    {:core-category "work", :project-identifier "proj-1"}
    
    

was missing this ...

  • take a few items at a time with partition,

Strange detail about clojure repl , namespaces and filenames,

  • looks like namespaces with hypens, expect clojure files with underscores,
  • My file is one/date-utils.clj and I tried to use it like so, but I got this message.
boot.user=> (use '[one.date-utils :as mydateutils])

java.io.FileNotFoundException: Could not locate one/date_utils__init.class or one/date_utils.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name.
boot.user=> 
  • Then i changed the file to one/date_utils.clj and problem solved.
boot.user=> (use '[one.date-utils :as mydateutils])
nil

concat vs using concat with apply

boot.user=> (concat [[5 6 7] [2 1 2]])
([5 6 7] [2 1 2])
boot.user=> (apply concat [[5 6 7] [2 1 2]])
(5 6 7 2 1 2)
boot.user=>
  • Basically concat takes sequences, and not a sequence of sequences
  • And (apply f args) has the power to take a sequence args and hand its individual components to f as bare parameters.
  • The first example was initially unintuitive, because I was trying to concat the output of a map,
(def full-list (concat
                (map (fn [x] (blah x))
                 input-vector)))
  • that was not working, and so i needed to update w/ an apply,
(def full-list (apply concat
                (map (fn [x] (blah x))
                 input-vector)))
  • Similarly to concat, conj can be used with apply in the same way...
app.core=> (def vec [0 1 2 3 4])
#'app.core/vec
app.core=> (apply conj vec [99 88])
[0 1 2 3 4 99 88]
  • So to explain the above, the normal form for conj is actually (conj vec 99 88), but if we have those args as a vector [99 88] then we can use apply to make the args vector be presented to conj as args.

doseq and for

user=> (for [x [1 2 3]] (+ x 5))
(6 7 8)
user=> (doseq [x [1 2 3]] (+ x 5))
nil
user=> (doseq [x [1 2 3]] (println x))
1
2
3
nil
  • If you want to build a new sequence based on other sequences, use for. If you want to do side-effects (printing, writing to a database, launching a nuclear warhead, etc) based on elements from some sequences, use doseq.

Feels like comp is one of the identities of clojure in that it helps keep you using simple functions

  • The order of operations is just like in maths ... (fºgºh)(x) := f(g(h(x)))
play.core=> ((comp #(- 4 %) #(* % 9) #(+ % 95)) 5)  
-896

Another way to combine , merge maps..

  • This feels like a very particular solution
playsync.core=> (def m1 {:foo 1 :boo 0})
#'playsync.core/m1
playsync.core=> (def m2 {:foo 2 :yoo 0})
#'playsync.core/m2
playsync.core=> 

playsync.core=> (merge-with + m1 m2)
{:foo 3, :boo 0, :yoo 0}

keys keywords from map

(let [
      {:keys [status headers body error]} {:status 0 :headers 1 :body 3 :error 5 :extra 88} 
      ]
  (println status body)
  )


your.app=> (let [
      #_=>       {:keys [status headers body error]} {:status 0 :headers 1 :body 3 :error 5 :extra 88} 
      #_=>       ]
      #_=>   (println status body)
      #_=>   )
0 3
nil
your.app=>

also keyword args arity

(comment
  ""
  (defn foof
    [a b & {:keys [op-fn]
            :or {op-fn +}}]
    (op-fn a b))

  (foof 4 5 :op-fn *)
  (foof 4 5 :op-fn #(str %1 ".." %2))

  )

list tables,

  • first get the faraday class thing ready.

    boot.user=> (use '[taoensso.faraday :as dynamo])
    
  • with a client-config hash defined in a separate clj file, here one/dynamo.clj is my file.

    (def client-config
      (if (:development env)
        {:access-key "OMGDEVELOPMENT"
         :secret-key "I_SHOULD_KEEP_THIS_SECRET!"
    
         ; Point the configuration at the DynamoDB Local
         :endpoint "http://localhost:8000"}
    
        {:endpoint "http://dynamodb.us-east-1.amazonaws.com"}
        )
    )
    
  • and use list-tables from the module/class thing,

    boot.user=> (use '[one.dynamo :as db])    ; `one/dynamo.clj`
    
    boot.user=> (dynamo/list-tables db/client-config)
    (:primes :projects :times)
    

create table

  • to get this env part to work, I didnt see any way to set the env vars in clojure, so I just set them on my shell,

    export development=true  # and this could have been anything that reduces to boolean true actually.
    
  • and the dynamodb local credentials dont matter it turns out,

    ; borrowing this from source at https://github.com/jamesleonis/serverless-in-clojure
    ; , https://medium.com/@jamesleonis/clojure-in-aws-serverless-dynamodb-cd5ed29027a5#.u29ighn8s  
    ; 
    (def client-config
      (if (:development env)
        {:access-key "OMGDEVELOPMENT"
         :secret-key "I_SHOULD_KEEP_THIS_SECRET!"
    
         ; Point the configuration at the DynamoDB Local
         :endpoint "http://localhost:8000"}
    
        {:endpoint "http://dynamodb.us-east-1.amazonaws.com"} ; this is the else part.
        )
    )
    
    (def table-name :my_table)
    
    (dynamo/create-table client-config table-name
                           [:index :n] 
                           {:throughput {:read 5 :write 5}
                            :block? true})
  • continuing to follow along from https://github.com/jamesleonis/serverless-in-clojure ,

    boot.user=> (use '[lesson-two.dynamo :as db] )  ; using some of the predefined functions from here,
    
    boot.user=> (db/list-primes)
    []
    boot.user=> (db/put-prime 0 2)
    nil
    boot.user=> (db/list-primes)
    [2]
    
    

Dependencies and the repl

  • It appears adding new dependencies into the build.boot file, and then running boot local repl again, downloads required dependencies and makes them useable for in the project.

  • directory structure for a project

    my-project-root/
        VERSION
        build.boot
        src/
            blah/
                foo.clj
                blarth.clj
    

sleeping...

(Thread/sleep 4000)

simple multithreading , from the Brave clojure book

(future (Thread/sleep 4000)
        (println "I'll print after 4 seconds"))
(println "I'll print immediately")

hmm this is weird. so dereferencing the future blocks?

(defn fight-crime
  []
  (let []
  (println "hi")
  (Thread/sleep 2000)
  (println "ho")
  (Thread/sleep 1000)
  (println "yo")
  5
  ))

(let [result (future (fight-crime))]
  (println "@: " @result)
  (println "snore. " )
  (println "@: " @result)
  (Thread/sleep 1000)
  (println "@: " @result)
)
  • Ah ok, but you can stop waiting.. so here we wait 10ms and then return "hmmf" if future isnt done yet.
(let [result (future (fight-crime))]
  (println "@: " (deref result 10 "hmmf"))
  (println "snore. " )
  (println "@: " (deref result 10 "hmmf"))
  (Thread/sleep 5000)
  (println "@: " (deref result 10 "hmmf"))
)

delays. cool

(def jackson-5-delay
  (delay (let [message "Just call my name and I'll be there"]
           (println "First deref:" message)
           message)))
(def gimli-headshots ["serious.jpg" "fun.jpg" "playful.jpg"])
(defn email-user
  [email-address]
  (println "Sending headshot notification to" email-address))
(defn upload-document
  "Needs to be implemented"
  [headshot]
  true)
(let [notify (delay (email-user "and-my-axe@gmail.com"))]
  (doseq [headshot gimli-headshots]
    (future (upload-document headshot)
            (force notify))))

Blocking thread in action...

; make a future which blocks on a promise. Then deliver promise in main thread and see what happens.
(def a-promise (promise))
(def futr
    (future 
        (def result (+ @a-promise 10))
        (Thread/sleep 5000)
        (println "result " result)
        result))
; 
(println "nothing yet: " (deref futr 10 "nothing."))
; deliver..    
(deliver a-promise 99)
(println "right after deliverin " (deref futr 10 "still nothin."))
(Thread/sleep 5500)
(println "had some time to think... " (deref futr))

delivering to promise multiple times?

  • hmm, how about the other way around... make some workers do something and have them all try deliver same promise. What will happen?
(def another-promise (promise))
(def d1 (delay 
                (Thread/sleep 6000)
                (deliver another-promise 6000)
                ))
;
(def d2 (delay 
                (Thread/sleep 4000)
                (deliver another-promise 4000)
                ))
;
(def d3 (delay 
                (Thread/sleep 1000)
                (deliver another-promise 1000)
                ))
; nothing there right?
(realized? another-promise)
; now run them all...
(doseq [a-worker [d1 d2 d3]]
        (future (force a-worker))
        )

(println "Check promise: " (deref another-promise 10 "nothin."))
(println "Check promise: " @another-promise)
  • hmm, for the above, strange that I tried but was not able to deref the delays. Error was
ClassCastException clojure.lang.Delay cannot be cast to java.util.concurrent.Future  clojure.core/deref-future (core.clj:2206)
  • given the yak butter search data...
(def yak-butter-international
  {:store "Yak Butter International"
    :price 90
    :smoothness 90})
(def butter-than-nothing
  {:store "Butter Than Nothing"
   :price 150
   :smoothness 83})
;; This is the butter that meets our requirements
(def baby-got-yak
  {:store "Baby Got Yak"
   :price 94
   :smoothness 99})

(defn mock-api-call
  [result]
  (Thread/sleep 1000)
  result)

(defn satisfactory?
  "If the butter meets our criteria, return the butter, else return false"
  [butter]
  (and (<= (:price butter) 100)
       (>= (:smoothness butter) 97)
       butter))
  • The original non concurrent code was ...
(time (some (comp satisfactory? mock-api-call)
            [yak-butter-international butter-than-nothing baby-got-yak]))
; => "Elapsed time: 3002.132 msecs"
; => {:store "Baby Got Yak", :smoothness 99, :price 94}
  • and a concurrent version...
(defn blah-func
    []
    (def best-butter-promise (promise))
    (time
        (doseq [some-butter [yak-butter-international butter-than-nothing baby-got-yak]]
            (future (if ((comp satisfactory? mock-api-call) some-butter)
                        (deliver best-butter-promise some-butter)
                        )))
                        )
    (time
        (println "result is: " @best-butter-promise))
    )
(blah-func)

=>
cloj-multiproc-play.core=> (blah-func)
"Elapsed time: 0.615436 msecs"
result is:  {:store Baby Got Yak, :price 94, :smoothness 99}
"Elapsed time: 1001.655823 msecs"
nil
cloj-multiproc-play.core=>

one more example , racing Bing vs Google

(def search-result-promise (promise))

(def bingurl  "https://www.bing.com/search?q=foobar")

(def googleurl "https://www.google.com/?gws_rd=ssl#q=foobar")

(doseq [url [bingurl googleurl]]
    (future (deliver search-result-promise (slurp url)
       ))
)

(def html1 (slurp "https://www.google.com/?gws_rd=ssl#q=foobar"))
  • my version of a hot dog machine that only dispenses max number of hot dogs...
(defn hot-dog-machine-v2
  [how-many-dogs-init]
  (let [in (chan)
        out (chan)]
    (go
      (loop [num-dogs how-many-dogs-init]
        ; if no hot dogs left, then done.
        (if (= num-dogs 0)
          true
          ; Otherwise 
          (do
            (println "Going to <! block on <in> now.")
            (<! in)
            (println "Now we have " num-dogs " dogs.")
            (println "Going to >! block on <out> now.")
            (>! out "hot dog")
            ))
        (recur (dec num-dogs))
        
        ))
    [in out]
    ))

; get channels..
(def machine-channels (hot-dog-machine-v2 5))
(def in (first machine-channels))
(def out (last machine-channels))

; ... dispensing them    
(println "one")
(>!! in "pocket lint")
(<!! out)

(println "two")
(>!! in "pocket lint")
(<!! out)

(println "three")
(>!! in "pocket lint")
(<!! out)

(println "four")
(>!! in "pocket lint")
(<!! out)

(println "five")
(>!! in "pocket lint")
(<!! out)
....

; that was fine except we went into negative hot dogs...
playsync.core=> (println "five")
five
nil
playsync.core=> (>!! in "pocket lint")
trueNow we have  1  dogs.
Going to >! block on <out> now.

playsync.core=> (<!! out)
Going to <! block on <in> now.
"hot dog"
playsync.core=> 

playsync.core=> (>!! in "pocket lint")
Now we have  -1  dogs.
true
Going to >! block on <out> now.
playsync.core=> (<!! out)
"hot dog"Going to <! block on <in> now.
  • .. update
(let [results-chan (chan)
    results-vector (atom [])]
    
    ; For several things in stuff-vec , start some async call that will throw results,
    ; into the results-chan
    (doseq [x stuff-vec]
        (do-something-async results-chan x))
        
    ; in this case, we take from the results-chan once they are ready, 
    ; and update (using conj) the atom results-vector
    (doseq [_ stuff-vec]
        (swap! results-vector conj (<!! results-chan)))
    )

swap syntax for updating atoms...

class cast exception

clojure.lang.LazySeq cannot be cast to clojure.lang.IFn
  • => some code is expecting a function, but is getting a LazySeq.

Amazonica and s3

  • This was not super obvious, because this example uses a java.io.ByteArrayInputStream with the the :input-stream parameter of the put-object function
  • But in my mind this feels more like an output stream since we're writing.
  • but maybe this is because we're reading from the payload .
(require ['amazonica.aws.s3 :as 'ss3])

(defn put-s3-obj
  [bucket-name s3key content]
  (let [payload (.getBytes content "UTF-8")
        input-stream (java.io.ByteArrayInputStream. payload)]
    (ss3/put-object :bucket-name bucket-name
                    :key s3key
                    :input-stream input-stream
                    ; :metadata {:server-side-encryption "AES256"} ;?
                    ;:file content
                    )))
                    

logging,

; require...  
[taoensso.timbre :as log]

; i have ended up using it like this, in a let, with fake variables,
(let 
[
var1 (myfunc "blah")
fake1 (log/info (str "var1: " var1))]
() ; do stuff)

I am used to python's zip

zip([1, 2, 3], ['a', 'b', 'c'])
# [(1, 'a'), (2, 'b'), (3, 'c')]

Interleaving and partitioning can do the same thing

(partition 2 (interleave '(1 2 3) '(4 5 6))) 
; => ((1 4) (2 5) (3 6))

; or more generally

(defn zip [& colls]
  (partition (count colls) (apply interleave colls)))

(zip '( 1 2 3) '(4 5 6))           ;=> ((1 4) (2 5) (3 6))

(zip '( 1 2 3) '(4 5 6) '(2 4 8))  ;=> ((1 4 2) (2 5 4) (3 6 8))

This was also a cool solution

user=> (map vector [1 2 3] [4 5 6])
([1 4] [2 5] [3 6])
user=> 

? If on a repl, but wanting to simulate a namespace ns in a project file

(in-ns 'foo.my-test)
  • hmm I thought that would give me access to the names in that namespace, but in my project, that didnt work...
  • My namespace in .. has
(ns foo.my-test
  (:require 
    [org.httpkit.client :as http]
    [org.httpkit.fake]))
  • and when i tried ...
user=> (in-ns 'foo.my-test)
#object[clojure.lang.Namespace 0x37b2f7ef "foo.my-test"]

foo.my-test=> (org.httpkit.fake/with-fake-http ["http://google.com/" "faked"
                              #_=>                  "http://flickr.com/" 500]
                              #_=>   (:body @(http/get "http://google.com/"))    ; "faked"
                              #_=>   (:status @(http/get "http://flickr.com/"))) ; 500

ClassNotFoundException org.httpkit.fake  java.net.URLClassLoader.findClass (URLClassLoader.java:381)

Also initially confused with ...

  • Starting new repl and cannot use require with raw library strings...
user=> (require [org.httpkit.client :as http])

CompilerException java.lang.ClassNotFoundException: org.httpkit.client, compiling:(/private/var/folders/mj/7bwn1wld4pscycn91fpjn1h40000gn/T/form-init5251815666209634293.clj:1:1) 
  • but use works.
user=> (use '[org.httpkit.client :as http])
WARNING: get already refers to: #'clojure.core/get in namespace: user, being replaced by: #'org.httpkit.client/get
nil
  • Hmm even so, I am using :as http, so why is use replacing the clojure.core/get in this namespace?

but using a fresh repl,

  • this worked:
user=> (require ['org.httpkit.client :as 'http])
nil
user=> 

user=> (def v1 @(http/get "https://www.braveclojure.com/organization/"))
#'user/v1
user=> (keys v1)
(:opts :body :headers :status)
  • So here, 'org.httpkit.client is a symbol and not a variable like org.httpkit.client .

from clojure for machine learnings..

(defn plot-points
  "plots sample points of a solution s"
  [s]
  (let [X (concat (:hidden s) (:observed s))
        Y (concat (:hidden-values s) (:observed-values s))]
    (view     ; NOTE save instead of view can save to a file.
      (add-points
        (xy-plot X Y) (:observed s) (:observed-values s)))))
        
; namespace...
; [incanter "1.5.4"]
(ns my-namespace
  (:use [incanter.charts :only [xy-plot add-points]]
        [incanter.core :only [view]])
   (:require [clojure.core.matrix.operators :as M]
             [clatrix.core :as cl]))
             
             
(ns my-namespace
   (:use clojure.core.matrix)
   (:require [clatrix.core :as cl]))


; from csv , to matrix..
(with-open [reader (io/reader "in-file.csv")]
  (doall
    (csv/read-csv reader)))
    
    
             

hmm... using is

  • so the library is built in, but you still have to start useing it..
boot.user=> (is (= 4 (+ 2 2)))

             java.lang.RuntimeException: Unable to resolve symbol: is in this context
clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: Unable to resolve symbol: is in this context, compiling:(/var/folders/7_/sbz867_n7bdcdtdry2mdz1z00000gn/T/boot.user2780891586981282255.clj:1:1)
boot.user=> 

boot.user=> 

boot.user=> (use 'clojure.test)
nil
boot.user=> (is (= 4 (+ 2 2)))
true

lein test

  • Running all tests in a file
lein test module/blah/test_file.py
  • Running specific deftest in module_hmm/blah/test_file.py called test-foo
lein test :only module-hmm.blah.test-file/test-foo
@namoopsoo
Copy link
Author

file io

  • read
(use 'clojure.java.io)
(with-open [rdr (reader "/tmp/test.txt")]
  (doseq [line (line-seq rdr)]
    (println line)))

  • write
(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt")]
  (.write wrtr "Line to be written"))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment