[{"cid":58076,"parent_cid":null,"body":"jolt: Clojure interpreter on Janet\r\n\r\nhttps://github.com/yogthos/jolt/\r\n\r\nLobsters: https://lobste.rs/s/gefcox/jolt_clojure_interpreter_on_janet","created_at":"2026-06-05T16:38:18.537Z","tags":["lisp","bot"],"orgs":[],"usrs":[],"created_by":"bot_lobsters","thumb":"https://opengraph.githubassets.com/0fad948a609838693a03b090f68f5c824a35ca86a8310c0d64df132a9d28b86e/yogthos/jolt","c_comments":1,"c_reactions":"","c_flags":0,"links":[],"flaggers":[],"author_ups":52,"author_downs":4,"author_posts_count":3915,"tag_ups":446,"tag_downs":77,"domain_ups":52,"domain_downs":4,"score":"2026-06-03T11:19:54.767Z","repost_ups":0,"mentions":[],"domains":["github.com","lobste.rs"],"comments":"1","reaction_count":"0","reaction_counts":{},"user_reactions":[],"child_comments":[{"cid":58093,"body":"> # [GitHub - yogthos/jolt: A Clojure interpreter running on Janet](https://github.com/yogthos/jolt/)\r\n>\r\n> A Clojure interpreter running on Janet. Jolt reads Clojure source, evaluates it with an interpreter written in pure Janet, and ships a Clojure-compatible standard library. The goal is a Janet-hosted SCI runtime — a minimal bootstrap that loads SCI's Clojure source as its standard library.\r\n>\r\n> ## Build\r\n>\r\n> git clone https://github.com/yogthos/jolt.git cd jolt git submodule update --init # pulls vendor/sci jpm build # compiles build/jolt\r\n>\r\n> Requires Janet ≥ 1.36 and jpm.\r\n>\r\n> ## Run\r\n>\r\n> build/jolt # start a REPL build/jolt file.clj [args] # run a file (binds *command-line-args* and *file*) build/jolt -e EXPR [args] # evaluate EXPR and print the result build/jolt -h # help\r\n>\r\n> The REPL accumulates multi-line forms until they balance:\r\n>\r\n> user=> (defn fib [n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))) #'user/fib user=> (map fib (range 10)) (0 1 1 2 3 5 8 13 21 34)\r\n>\r\n> Running a file evaluates its top-level forms:\r\n>\r\n> $ echo '(println \"hello\" (* 6 7))' > hello.clj $ build/jolt hello.clj hello 42\r\n>\r\n> ## Use as a library\r\n>\r\n> (use jolt/api) (def ctx (init)) (eval-string ctx \"(+ 1 2)\") # → 3 (eval-string ctx \"(map inc [1 2 3])\") # → [2 3 4]\r\n>\r\n> (init) returns a context with clojure.core loaded. Each context is isolated; use separate contexts for separate environments.\r\n>\r\n> ## Host interop\r\n>\r\n> Jolt exposes CLJS-style host interop through . on any Janet table or struct — a field holding a function is called with the receiver as the first argument:\r\n>\r\n> (def obj {:greet (fn [self name] (str \"Hello \" name))}) (. obj greet \"Alice\") ; → \"Hello Alice\" (.-greet obj) ; field access (reader sugar for (. obj :greet))\r\n>\r\n> Janet's standard library is reachable through jolt.interop (and the jolt.shell / jolt.http helpers built on it):\r\n>\r\n> (require '[jolt.interop :as j]) (j/janet-type [1 2]) ; → :tuple (j/janet-table-keys {:a 1 :b 2}) ; → [:b :a]\r\n>\r\n> ## Differences from Clojure\r\n>\r\n> Jolt targets Clojure semantics but runs on Janet, not the JVM. The notable divergences:\r\n>\r\n> - Host platform. No JVM and no Java interop — import, gen-class, proxy of Java classes, and java.* are unavailable. instance? recognizes a small set of built-in types (clojure.lang.Atom, Number, String, …).\r\n>\r\n> - Numbers. Janet integers and doubles. (/ 1 3) is 0.3333… and large products lose precision. No ratios or BigDecimal (ratio? is always false, bigdec falls back to a double); bigint/biginteger use Janet's 64-bit int/s64, not arbitrary precision. The auto-promoting +'/-'/*'/inc'/dec' are aliases for the plain ops, since Janet numbers don't overflow. quot/rem/mod follow Clojure's sign rules. The symbolic values ##Inf/##-Inf/##NaN read, and infinite?/NaN? work. Janet represents an integer and an integer-valued double identically, so 1 and 1.0 are indistinguishable: (float?/double? 1.0) is false and (int? 1.0) is true — float?/double? are true only for values with a fractional part or ##Inf/##NaN.\r\n>\r\n> - Collections. By default Jolt uses immutable persistent data structures: vectors are 32-way branching tries (structural-sharing persistent vectors with O(log₃₂ n) conj/assoc/nth), lists are persistent singly-linked cons cells (O(1) conj/cons prepend with structural sharing), and maps/sets are persistent hash structures. Value equality and sequence operations are Clojure-compatible, but hash-map/hash-set iteration order is unspecified and differs from Clojure — use sorted-map/sorted-set when order matters.\r\n>\r\n> …","orgs":[],"tags":["lisp","bot"],"usrs":[],"c_flags":0,"comments":0,"created_at":"2026-06-05T17:25:26.492836+00:00","created_by":"bot_reader","parent_cid":58076,"child_comments":[],"user_reactions":[],"reaction_counts":{}}]}]