Skip to content

Commit eaf4085

Browse files
authored
Add explanations to the Scilttle nRepl notebook (#271)
* clean show-expression * Add explanations to notebook on Scittle nRepl
1 parent 9946742 commit eaf4085

File tree

2 files changed

+68
-37
lines changed

2 files changed

+68
-37
lines changed

src/mentat_collective/emmy/appendix_scittlerepl.clj

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@
22
:clay {:title "The Scittle Repl"
33
:quarto {:author :kloimhardt
44
:type :post
5+
:description "This Clay notebook has its Scittle nRepl built in, so you can connect your editor to its ClojureScript side."
56
:date "2025-12-04"
67
:image "appendix_scittlerepl.png"
78
:category :libs
89
:tags [:scittle :repl]}}}
910
(ns mentat-collective.emmy.appendix-scittlerepl
1011
(:require
12+
[nrepl.core :as repl]
1113
[sci.nrepl.browser-server :as nrepl]
1214
[scicloj.kindly.v4.api :as kindly]
1315
[scicloj.kindly.v4.kind :as kind]))
1416

15-
;; This Clay notebook has its Scittle nrepl built in, so you can connect your editor to its ClojureScript side.
17+
;; This HTML page, as any Civitas notebook, is hosted by [Clay](https://github.com/scicloj/clay). The notebook is meant to be changed in a local Civitas instance. This is because it is all about connecting your local editor to the browser, i.e. the ClojureScript side of this notebook.It is about sending code from your editor to an in browser process.
1618

1719
;; ## Starting the Scittle Repl of this Clay Notebook
1820

@@ -22,9 +24,25 @@
2224
;; (nrepl/start! {:nrepl-port 1339 :websocket-port 1340})
2325
;;```
2426

25-
;; ... and (re)load this notebook within your local Clay instance.
27+
;; ... and (re)load this notebook within your local Clay instance. Then again, comment the line above and reload the notebook (again).
2628

27-
;; Then open an arbitrary (not .clj but) .cljs ClojureScript file.
29+
;; Below you should see a hash-map that contains the entry `:value "3"`
30+
31+
(defn connect-and-eval
32+
[host port code]
33+
(with-open [conn (repl/connect :host host :port port)] ; Establishes the connection
34+
(-> (repl/client conn 1000) ; Creates a client with a message timeout
35+
(repl/message {:op "eval" :code code}) ; Sends an "eval" message
36+
(doall)
37+
(clojure.pprint/pprint)
38+
#_(repl/response-values))))
39+
40+
(if (not @@#'nrepl/!socket)
41+
"not connected"
42+
(connect-and-eval "localhost" 1339 "(+ 1 2)"))
43+
44+
45+
;; Next, open an arbitrary (not .clj but) .cljs ClojureScript file.
2846

2947
;; In your local editor, open a Repl connection. For example in Emacs/Cider, this means the following 5 steps: (I) *(sesman-start)* (II) choose cider-connect-cljs (III) select localhost (IV) port 1339, followed by (V) the REPL type nbb.
3048

@@ -34,6 +52,12 @@
3452
(kind/hiccup
3553
[:img {:src "GClef.svg"}])
3654

55+
;; ## Some Explanations
56+
57+
;; - Scittle is the ClojureScript runtime executing in the browser
58+
;; - `browser-server` is a "broker" process that receives instructions from your editor (send form, send file), sends it to Scittle, and returns the result.
59+
;; - The reason browser-server exists is because editors have nRepl integrations, but nothing to talk to Scittle directly.
60+
;; - Scittle is listening on a websocket which is different from an nRepl socket. Nontheless, it performs the same function.
3761

3862
;; ## The Scittle State
3963

@@ -44,7 +68,6 @@
4468
{"Action" ["Reload browser" "Save this very notebook .clj file" "Save any .cljs file"]
4569
"Clean Scittle state" ["yes" "yes" "no"]})
4670

47-
4871
;; The Scittle Repl looses its state when the browser window is reloaded. This also means that the Scittle Repl looses its state when this very notebook .clj file is reloaded. As opposed to that, the Clojure/JVM state persists in any case. In fact, this very notebook, in using defonce, relies on a persistent Clojure/JVM state. But the possibility to produce a clean Scittle slate via browser reload can be of great advantage especially for the (domain-expert but) Repl-novice.
4972

5073
;; This notebook works best when Clay is started in file-watcher mode via `clojure -M:clay`. It is not a good idea to open, next to the Scittle Repl, also a Clojure/JVM Repl connection. At least in my setup, opening more than one Repl connection leads to unstable behaviour. Act at your own discretion.
@@ -53,6 +76,10 @@
5376

5477
;; In sum, while saving a .cljs file keeps the Scittle state, saving this very notebook .clj file cleans the Scittle state. But as I can only want you to happily repl in .cljs files exclusively, further changing and loading of this very notebook is not necessary. Of course, you are free to change and save this very notebook .clj file as often as you like, but make sure all your .cljs files are saved before you do so. Any unsaved Scittle .cljs file keeps this very notebook from reloading on change.
5578

79+
;; ## With Clay, you can talk to Scittle without nRepl, but it won't answer (yet)
80+
;; Clay already has a websocket connection from the Clojure process to the HTML page (and therefore Scittle). This is how Clay loads .cljs files when in live-reload mode. It sends the code over the websocket and calls Scittle. `scicloj.clay.v2.server/scittle-eval-string!` is called when a cljs file is changed, and `scicloj.clay.v2.server/communication-script` contains the JavaScript that does `window.scittle.core.eval_string(code);`
81+
;; So there is already a direct bridge from the Clojure Clay process to the Scittle process. However the current implementation does not send a result back to Clay.
82+
5683
;; ## The inner workings of Scittle and sci.nrepl
5784

5885
;; The following code is just to reveal the inner workings, you should already be able to happily repl in your .cljs file.
@@ -66,13 +93,13 @@
6693
;;[:script {:src "https://cdn.jsdelivr.net/npm/scittle@0.6.22/dist/scittle.nrepl.js"}]
6794
])
6895

69-
;; ## Also with Babashka
96+
;; ## Connect to Scittle and the browser without Java
7097

71-
;; It is possible to start the nrepl server entirely without Java.
98+
;; The main advantage of this nRepl method is that it is possible to start the nRepl server entirely without Java (and thus entirely without Clay).
7299

73100
;; Make sure that, in your local directory, there exists the file [browser_server.clj](https://github.com/ClojureCivitas/clojurecivitas.github.io/blob/main/src/mentat_collective/emmy/browser_server.clj)
74101

75-
;; Then in the terminal, start babashka in the following way
102+
;; Then in the terminal, start [Babashka](https://babashka.org) in the following way
76103

77104
^:kindly/hide-code
78105
(kind/code

src/mentat_collective/emmy/sicm_ch01.clj

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,17 @@
1616
[mentat-collective.emmy.scheme :refer [define-1 let-scheme lambda]]
1717
[civitas.repl :as repl]))
1818

19+
;; The following examples are taken from the MIT open-access book [Structure and Interpretation of Classical Mechanics (SICM)](https://mitp-content-server.mit.edu/books/content/sectbyfn/books_pres_0/9579/sicm_edition_2.zip/chapter001.html).
20+
21+
^:kindly/hide-code
22+
(do
23+
"if you `prod` to `false`, the browser will be busy calculating, be patient"
24+
(def prod true))
25+
1926
^:kindly/hide-code
2027
(def md
2128
(comp kindly/hide-code kind/md))
2229

23-
(md "The following examples are taken from the MIT open-access book [Structure and Interpretation of Classical Mechanics (SICM)](https://mitp-content-server.mit.edu/books/content/sectbyfn/books_pres_0/9579/sicm_edition_2.zip/chapter001.html).")
24-
2530
(md "Another notebook can be found on the [Road to Reality website](https://reality.mentat.org/essays/reality/introduction#welcome-to-the-road-to-reality!) by [Sam Ritchie](https://roadtoreality.substack.com/p/the-first-executable-essay-is-live), the author (along with [Colin Smith](https://github.com/littleredcomputer)) of [Emmy, the Computer Algebra System](https://emmy.mentat.org).")
2631

2732
;; For interactivity, I have some
@@ -73,45 +78,44 @@
7378
(require emmy-mn)))
7479

7580
^:kindly/hide-code
76-
(define show-exp (comp str simplify))
81+
(kind/scittle
82+
'(defn show-expression [e]
83+
(simplify e)))
7784

7885
^:kindly/hide-code
7986
(kind/scittle
80-
'(defn show-expression [b & c]
81-
(if (keyword? b)
82-
(show-exp (first c))
83-
(show-exp b))))
87+
'(def show-tex-expression show-expression))
8488

8589
^:kindly/hide-code
8690
(def tex (comp kind/tex emmy.expression.render/->TeX simplify))
8791

8892
^:kindly/hide-code
89-
(defmacro show-expression [b & c]
90-
(let [prod true ;; if you set this to false, the browser will be busy calculating, be patient
91-
reag-comp (fn [b] (let [server-erg (show-exp (eval b))]
92-
(list 'kind/reagent
93-
[:div (list 'quote
94-
(list 'let ['a (list 'show-exp b)]
95-
(list 'if 'false #_(list '= server-erg 'a)
96-
[:tt 'a]
97-
[:div
98-
(when (not prod)
99-
[:div
100-
[:tt 'a]
101-
[:p]])
102-
[:tt server-erg]])))])))]
103-
(case b
104-
:tex
105-
(if prod
106-
(list 'tex (first c))
107-
(reag-comp (first c)))
108-
(if prod
109-
(list 'simplify b)
110-
(reag-comp b)))))
93+
(define show-exp (comp str simplify))
94+
95+
^:kindly/hide-code
96+
(defn reag-comp [b]
97+
(let [server-erg (show-exp (eval b))]
98+
(list 'kind/reagent
99+
[:div (list 'quote
100+
(list 'let ['a (list 'show-exp b)]
101+
[:div
102+
(when (not prod)
103+
[:div
104+
[:tt 'a]
105+
[:p (list 'str (list '= server-erg 'a))]])
106+
[:tt server-erg]]))])))
107+
108+
^:kindly/hide-code
109+
(defmacro show-expression [e]
110+
(if prod
111+
(list 'simplify e)
112+
(reag-comp e)))
111113

112114
^:kindly/hide-code
113115
(defmacro show-tex-expression [e]
114-
(list 'show-expression :tex e))
116+
(if prod
117+
(list 'tex e)
118+
(reag-comp e)))
115119

116120
^:kindly/hide-code
117121
(define velocities velocity)

0 commit comments

Comments
 (0)