Overthunk

Ch 10 - 12 Spree!

Jul 20, 2020


Contents

What I learned today

Concurrent-ify tasks that are completely independent of each other. No risk since there is no shared access to a mutable state

pmap -> each application of the mapping function happens on a separate thread

;; (time (dorun (map clojure.string/lower-case orc-names)))
;; "Elapsed time: 295.426771 msecs"

;; (time (dorun (pmap clojure.string/lower-case orc-names)))
;; "Elapsed time: 129.370606 msecs"

There is some overhead involved with creating and coordinating threads. grain size - amount of work done by each parallelized task. Sometimes, the overhead can be more than the time for each function application.

Solution to make pmap take less time is to increase the grain size. (applying the mapping function to two elements instead of one)

Chapter 10 Exercises

  1. Create an atom with the initial value 0, use swap! to increment it a couple of times, and then dereference it.
(def a (atom 0))
(swap! a inc)
(swap! a inc)
@a
;; => 2
  1. Create a function that uses futures to parallelize the task of downloading random quotes fromhttp://www.braveclojure.com/random-quote
(defn get-quote [] (slurp "https://www.braveclojure.com/random-quote"))

(defn quote-word-count
  [num-quotes]
  (let [word-freq (atom {})]
    (dotimes [i num-quotes]
      (deref (future (let [cur-quote (as-> (get-quote) x
                                       (clojure.string/replace x #"--" "")
                                       (clojure.string/replace x #"\n" "")
                                       (clojure.string/lower-case x))
                           cur-freq (frequencies (clojure.string/split cur-quote #" "))]
                       (swap! word-freq merge cur-freq)))))
    (deref word-freq)))

(println (quote-word-count 5))
  1. Create representations of two characters in a game. The first character has 15 hit points out of a total of 40. The second character has a healing potion in his inventory. Use refs and transactions to model the consumption of the healing potion and the first character healing.
(def player1 (ref {:handle "Kirito" :hitpoints 15/40 :inventory {:sword "Dual Blades" :healing-potion 0}}))
(def player2 (ref {:handle "Asuna" :hitpoints 33/40 :inventory {:healing-potion 1}}))

(dosync
 (alter player2 update-in [:inventory :healing-potion] dec)
 (alter player1 assoc :hitpoints 40/40))

@player1
;; => {:handle "Kirito",
;;     :hitpoints 40/40,
;;     :inventory {:sword "Dual Blades", :healing-potion 0}}

@player2
;; => {:handle "Asuna", :hitpoints 33/40, :inventory {:healing-potion 0}}

Chapter 11

core.async describes a useful model for concurrency and processes.

Chapter 12 - JVM

Working with the JVM!

The JVM translates code into low-level instructions called Java Bytecode. JIT compilation - A running JVM executes bytecode by translating it on the fly into into machine code that its host will understand.

Interop

Call methods on an object using (.methodName object). This uses macros to expand the dot special form.

(macroexpand-1 '(.toUpperCase "By Bluebeard's bananas!"))
; => (. "By Bluebeard's bananas!" toUpperCase)

(macroexpand-1 '(.indexOf "Let's synergize our bleeding edges" "y"))
; => (. "Let's synergize our bleeding edges" indexOf "y")

(macroexpand-1 '(Math/abs -3))
; => (. Math abs -3)

Create objects with (new ClassName opt-args) or (Classname. opt-args)

Importing has the same effect as it does in Java -> You can use classes without having to type out the entire package prefix.

(import java.util.Stack.)

Within a ns macro -

(ns pirate.talk
  (:import [java.util Date Stack]
           [java.net Proxy URI]))

You can use seq functions to read data from a stack. But can’t use conj or into

(doto (java.util.Stack.)
  (.push "Latest ep of GoT")
  (.push "Whoops, I meant something else"))

;; doto returns the object rather than the value of the method calls

(System/getenv)

(System/getProperty "user.dir")
;; => "/Users/mani/repos/learn-clojure-in-public/code/clojure-noob"

(System/getProperty "java.version")
;; => "14.0.1"

IO with Clojure -

(spit "/tmp/hercules-todo-list"
      "- kill dat lion brov
- chop up what nasty multi-headed snake thing")

(slurp "/tmp/hercules-todo-list")
;; => "- kill dat lion brov\n- chop up what nasty multi-headed snake thing"

(with-open [todo-list-str (clojure.java.io/reader "/tmp/hercules-todo-list")]
  (println (first (line-seq todo-list-str))))
;; => kill dat lion bruv

Takeaway

I went through quite a few different pieces of information about Clojure today. But the downside is that I didn’t gain a deep understanding of it. So I’ll have to go back and understand it.

Today’s tally -