View simple-stats.clj
;; simple stats computed using xforms transducers
=> (require '[net.cgrand.xforms :as x])
=> (into {}
(x/by-key #(> % 0.5)
(x/transjuxt {:min x/min :max x/max :avg x/avg :sd x/sd}))
(repeatedly 1e6 rand))
{:min 1.0036018363024368E-6,
:max 0.4999987525112054,
:avg 0.2502046186242099,
View core.cljc
;; SEE:
;; macros and code in a single cljc working across clj, cljs and self-hosted cljs
;; require clojurescript from master
(ns foo.core
#?(:cljs (:require-macros
[net.cgrand.meta-macros :refer [macros no-macros]]
[foo.core :refer [add]])
:clj (:require
View advent2016-day4.clj
;; breaking into separate file because inputs are too big
(defn checksum [name]
(apply str (take 5 (map first (sort (fn [[l n] [l' n']] (or (> n n') (and (= n n') (< (int l) (int l'))))) (-> name frequencies (dissoc \-)))))))
(defn day4-1 [input]
(->> (re-seq #"([-a-z]+)-(\d+)\[([a-z]+)\]" input)
(filter (fn [[_ name sector-id sum]] (= (checksum name) sum)))
(map (fn [[_ name sector-id sum]] (Long/parseLong sector-id)))
(reduce +)))
View rollup.clj
(require '[net.cgrand.xforms :as x])
(defn rollup [dimensions valfn]
(let [[dim & dims] (reverse dimensions)]
(fn [xform dim]
(x/by-key dim xform)
{:detail (x/into {})
View advent2016.clj
(ns advent2016)
;; day1
(def day1-input "R4, R3, R5, L3, L5, R2, L2, R5, L2, R5, R5, R5, R1, R3, L2, L2, L1, R5, L3, R1, L2, R1, L3, L5, L1, R3, L4, R2, R4, L3, L1, R4, L4, R3, L5, L3, R188, R4, L1, R48, L5, R4, R71, R3, L2, R188, L3, R2, L3, R3, L5, L1, R1, L2, L4, L2, R5, L3, R3, R3, R4, L3, L4, R5, L4, L4, R3, R4, L4, R1, L3, L1, L1, R4, R1, L4, R1, L1, L3, R2, L2, R2, L1, R5, R3, R4, L5, R2, R5, L5, R1, R2, L1, L3, R3, R1, R3, L4, R4, L4, L1, R1, L2, L2, L4, R1, L3, R4, L2, R3, L1, L5, R4, R5, R2, R5, R1, R5, R1, R3, L3, L2, L2, L5, R2, L2, R5, R5, L2, R3, L5, R5, L2, R4, R2, L1, R3, L5, R3, R2, R5, L1, R3, L2, R2, R1")
(defn day1-1 [input]
(let [[[x y]] (reduce (fn [[[x y] [dx dy]] [_ dir n]]
(let [n (Long/parseLong n)
[dx dy] (case dir
"R" [dy (- dx)]
View not-a-good-idea.clj
(defn mid [a b] (/ (+ a b) 2.0))
(count (take-while #(not= 1.0 %) (iterate #(mid 1 %) 2)))
=> 53
; 53 is not random but tied to the fact that the fraction part of a double is stored on 52 bits

The "Double bananas" (( smell

Usual offenders:

  • inside a threading macro to "protect" a fn; action: stop the threading or refactor it with as->
  • ((comp f g) x) or ((juxt f g) x) or ((partial f x) y) (the three most frequent); action: unroll the comp/juxt/partial
  • in other cases it's worth considering giving the poor thing a name

In general I find ((f x) y z) hard to follow, harder than (g (f x) z) for example. In the second case the role of (f x) is given by g (eg (f x) must be a predicate). In the first case the role of (f x) is given by f alone. To recap: with (g (f x) z) you have two sources of information to infer the nature of (f x) (and may realize there's a glitch when the two sources are discordant), with ((f x) y z) you only have one source of information.

View xlife.clj
(ns xlife
(:require [net.cgrand.xforms :as x]))
;; xforms is a library of transducers
(defn xstep [cells]
(into #{}
; a comprenhension to generate neighbours
(x/for [[x y] %
View set-game.clj
;; the SET game in clojure.spec
;; inspired by
(require '[clojure.spec :as s])
(s/def ::shape #{:oval :diamond :squiggle})
(s/def ::color #{:red :purple :green})
(s/def ::value #{1 2 3})
(s/def ::shading #{:solid :striped :outline})
(s/def ::card (s/keys :req [::shape ::color ::value ::shading]))
View spec-cfg.clj
;; warm up: balancing
=> (s/def ::balanced
(s/* (s/cat :open #{'<} :children ::balanced :close #{'>})))
=> (s/conform ::balanced '[< < > < > > < >])
[{:open <, :children [{:open <, :close >} {:open <, :close >}], :close >} {:open <, :close >}]
=> (s/conform ::balanced '[< < > < < > > > < >])
[{:open <, :children [{:open <, :close >} {:open <, :children [{:open <, :close >}], :close >}], :close >} {:open <, :close >}]
;; infix to prefix