joetjen.net
EN DE
Programming language

Examples

Slightly larger pieces, each run against v0.60.0 with the output it produced.

In development · v0.60

Word frequencies

A pipeline over the standard library. Every step takes the text or collection first, so -> threads it through.

(defn top-words "The `n` most frequent words in `text`."
  [text n] :spec [string integer -> seq]
  (-> text
      string/lower-case
      (string/split " ")
      (seq/remove string/blank?)
      seq/frequencies
      map/to-pairs
      (seq/sort-by (fn [#(_word count)] (- count)))
      (seq/take n)))

(top-words "the cat and the hat and the bat" 2)
; => (#("the" 3) #("and" 2))

Validation that reports every error

Map destructuring in the parameter list, with for the happy path and result/collect to gather every failure instead of stopping at the first. Prices are decimals, so the total is exact.

(defn- positive [field value]
  (if (> value 0)
    #(:ok value)
    #(:error (str field " must be positive"))))

(defn check-order [{:qty qty :price price}]
  (with [#(:ok checked) (result/collect [(positive "qty" qty) (positive "price" price)])]
    #(:ok {:qty (seq/first checked) :price (seq/nth checked 1) :total (* qty price)})))

(check-order {:qty 3 :price 1.25M})
; => #(:ok {:total 3.75M, :qty 3, :price 1.25M})
(check-order {:qty 0 :price -1})
; => #(:error ("qty must be positive" "price must be positive"))

A supervised actor

Let it crash, in Praxis: a running total in its own process, a supervisor that restarts it, and an application that makes it fail on purpose.

src/shop/till.prax
(ns shop.till "A running total, kept in its own process." (:behaviour praxis.actor))

(defn init [from] #(:ok from))
(defn handle-call [:total _from state] #(:reply state state))
(defn handle-cast
  ([#(:add price) state] #(:noreply (+ state price)))
  ([:crash _state] (throw :asked-to-fail)))
(defn start-link [from] (praxis.actor/start-link shop.till from {:name shop.till}))
src/shop/tree.prax
(ns shop.tree "Everything the shop runs." (:behaviour praxis.supervisor))
(require [praxis.supervisor :as sup])

(defn init [_argument]
  #(:ok #((sup/flags :one-for-one) (list (sup/child shop.till 0)))))

The application starts the tree, adds 1.50, 2.25 and 0.99, asks for the total, casts :crash, and asks again. prx run:

total: 4.74
22:52:30.564 [error] shop.till stopped: #(:bad_return_value #(:asked-to-fail {}))
It was casting :crash
restarted: true
total after restart: 0

One source, two machines

The repository’s portable example is a single program run twice — prx run on the BEAM, and prx compile --target js followed by node — with the two outputs compared line by line. The JavaScript build writes one ES module per namespace, a source map and TypeScript declarations generated from the specs. Across the whole conformance suite, the BEAM and JavaScript agree on 877 of 877 cases.