Slide 1

Slide 1 text

ClojureScript ClojureScript The Good Parts The Good Parts

Slide 2

Slide 2 text

カマイルカ /laʒenɔʁɛ̃k/ カマイルカ /laʒenɔʁɛ̃k/ lagénorhynque lagénorhynque (defprofile lagénorhynque :name "Kent OHASHI" :languages [Clojure Haskell Python Scala English français Deutsch русский] :interests [programming language-learning mathematics] :contributing [github.com/japan-clojurians/clojure-site-ja])

Slide 3

Slide 3 text

Lisp × JavaScript Lisp × JavaScript

Slide 4

Slide 4 text

What is ClojureScript? What is ClojureScript?

Slide 5

Slide 5 text

(CLJS) (CLJS) compiler for Clojure that targets JavaScript cf. (JVM/Java), (CLR/C#) simple and powerful functional Lisp ClojureScript ClojureScript Clojure ClojureCLR

Slide 6

Slide 6 text

Use Cases Use Cases SPA: / , , , etc. React Native: Electron Node.js AWS Lambda etc. Reagent re-frame Rum Om re-natal

Slide 7

Slide 7 text

Try CLJS with Try CLJS with Lumo Lumo $ npm install -g lumo-cljs $ lumo cljs.user=> (defn hello [& {:keys [to] #_=> :or {to "world"}}] #_=> (println (str "Hello, " to "!"))) #'cljs.user/hello cljs.user=> (hello) Hello, world! nil cljs.user=> (hello :to "ClojureScript") Hello, ClojureScript! nil

Slide 8

Slide 8 text

Good Parts Good Parts

Slide 9

Slide 9 text

Lisp Lisp

Slide 10

Slide 10 text

S-expressions (sexp) S-expressions (sexp) simple rule: (op arg ...) various kinds of functions macros special forms structural editing , , etc. ParEdit Parinfer

Slide 11

Slide 11 text

Collection Literals Collection Literals cf. function de nition cljs.user=> '(1 2 3) ; list (1 2 3) cljs.user=> [1 2 3] ; vector [1 2 3] cljs.user=> #{1 2 3} ; set #{1 2 3} cljs.user=> {:a 1 :b 2 :c 3} ; map {:a 1, :b 2, :c 3} (defn hello [& {:keys [to] :or {to "world"}}] (println (str "Hello, " to "!")))

Slide 12

Slide 12 text

Lisp Macros Lisp Macros compile-time metaprogramming code as data sexp -> sexp

Slide 13

Slide 13 text

e.g. for macro (sequence comprehension) ;; ClojureScript cljs.user=> (for [x (range 10) #_=> :when (odd? x)] #_=> (* x x)) (1 9 25 49 81) cljs.user=> (macroexpand-1 #_=> '(for [x (range 10) #_=> :when (odd? x)] #_=> (* x x))) (cljs.core$macros/let [iter__9116__auto__ (cljs.core$macros/fn ,,, # Python >>> [x ** 2 for x in range(10) if x % 2 != 0] [1, 9, 25, 49, 81] -- Haskell > [x ^ 2 | x <- [0..9], odd x] [1,9,25,49,81]

Slide 14

Slide 14 text

REPL-driven Development REPL-driven Development Create a ClojureScript project with Leiningen $ brew install leiningen $ lein new figwheel cljs-demo # e.g. "figwheel" template $ cd cljs-demo $ lein figwheel # or `cider-jack-in-clojurescript` on Emacs

Slide 15

Slide 15 text

editor-integrated REPL (e.g. Emacs & ) CIDER

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

browser REPL for front-end development

Slide 18

Slide 18 text

Changes are automatically loaded in the browser

Slide 19

Slide 19 text

Functional Functional Programming Programming

Slide 20

Slide 20 text

Immutable Persistent Immutable Persistent Collections Collections no mutations, no side e ects high performance ljs.user=> (conj [1 2] 3) ; add an element to vector [1 2 3] cljs.user=> (conj '(1 2) 3) ; add an element to list (3 1 2) cljs.user=> (conj #{1 2} 3) ; add an element to set #{1 2 3} cljs.user=> (assoc {:a 1 :b 2} :c 3) ; add an entry to map {:a 1, :b 2, :c 3}

Slide 21

Slide 21 text

Map and Sequence Map and Sequence as Core Abstractions as Core Abstractions maps: get, assoc sequences: first, rest, cons lazy sequences rare to de ne something like classes or algebraic data types few data abstractions and many functions

Slide 22

Slide 22 text

e.g. maps for modelling entities cljs.user=> (ns geometry.sphere) nil geometry.sphere=> (defn surface-area [{::keys [radius]}] #_=> (* 4 Math/PI (Math/pow radius 2))) #'geometry.sphere/surface-area geometry.sphere=> (defn volume [{::keys [radius]}] #_=> (* 4/3 Math/PI (Math/pow radius 3))) #'geometry.sphere/volume geometry.sphere=> #::{:radius 2} #:geometry.sphere{:radius 2} geometry.sphere=> (surface-area #::{:radius 2}) 50.26548245743669 geometry.sphere=> (volume #::{:radius 2}) 33.510321638291124

Slide 23

Slide 23 text

e.g. typical sequence manipulations cljs.user=> (defn leibniz [n-terms] #_=> (->> (iterate #(+ % 2) 1) #_=> (map / (cycle [1 -1])) #_=> (take n-terms) #_=> (apply +) #_=> (* 4.0))) #'cljs.user/leibniz cljs.user=> (leibniz 1000) 3.140592653839794 cljs.user=> (leibniz 10000) 3.1414926535900345 cljs.user=> (leibniz 100000) 3.1415826535897198

Slide 24

Slide 24 text

Data > Functions > Macros Data > Functions > Macros data-driven/oriented design examples libraries: , , frameworks: , , Honey SQL Hiccup Reagent Duct Pedestal re-frame

Slide 25

Slide 25 text

speci cation system similar to Racket's cf. gradual typing e.g. (Typed Clojure) clojure.spec clojure.spec contract system core.typed

Slide 26

Slide 26 text

Common mistakes with maps ... ;; typo in key name geometry.sphere=> (surface-area #::{:radias 2}) 0 ;; incorrect value type geometry.sphere=> (volume #::{:radius "2"}) 33.510321638291124

Slide 27

Slide 27 text

Introduce clojure.spec geometry.sphere=> (require '[cljs.spec.alpha :as s #_=> :include-macros true]) nil geometry.sphere=> (s/def ::radius (s/and number? pos?)) :geometry.sphere/radius geometry.sphere=> (s/def ::sphere (s/keys :req [::radius])) :geometry.sphere/sphere geometry.sphere=> (s/fdef surface-area #_=> :args (s/cat :sphere ::sphere) #_=> :ret number?) geometry.sphere/surface-area geometry.sphere=> (s/fdef volume #_=> :args (s/cat :sphere ::sphere) #_=> :ret number?) geometry.sphere/volume

Slide 28

Slide 28 text

Instrument specs ※ add as a dependency (cf. ) geometry.sphere=> (require '[cljs.spec.test.alpha :as stest #_=> :include-macros true]) nil geometry.sphere=> (stest/instrument) [geometry.sphere/surface-area geometry.sphere/volume] test.check CLJS-1792 # for example $ lumo -c src:~/.m2/repository/org/clojure/test.check-0.9.0.jar

Slide 29

Slide 29 text

Spec-instrumented surface­area function geometry.sphere=> (surface-area #::{:radius 2}) 50.26548245743669 geometry.sphere=> (surface-area #::{:radias 2}) Call to #'geometry.sphere/surface-area did not conform to spec: In: [0] val: #:geometry.sphere{:radias 2} fails spec: :geometry.sphere/sphere at: [:args :sphere] predicate: (contains? % :geometry.sphere/radius) :cljs.spec.alpha/spec #object[cljs.spec.alpha.t_cljs$spec$alpha 10508] :cljs.spec.alpha/value (#:geometry.sphere{:radias 2}) :cljs.spec.alpha/args (#:geometry.sphere{:radias 2}) :cljs.spec.alpha/failure :instrument ,,,

Slide 30

Slide 30 text

Spec-instrumented volume function geometry.sphere=> (volume #::{:radius 2}) 33.510321638291124 geometry.sphere=> (volume #::{:radius "2"}) Call to #'geometry.sphere/volume did not conform to spec: In: [0 :geometry.sphere/radius] val: "2" fails spec: :geometry.sphere/radius at: [:args :sphere :geometry.sphere/radius] predicate: number? :cljs.spec.alpha/spec #object[cljs.spec.alpha.t_cljs$spec$alpha 10508] :cljs.spec.alpha/value (#:geometry.sphere{:radius "2"}) :cljs.spec.alpha/args (#:geometry.sphere{:radius "2"}) :cljs.spec.alpha/failure :instrument ,,,

Slide 31

Slide 31 text

Land of Lisp invades JS world!! Land of Lisp invades JS world!!

Slide 32

Slide 32 text

Further Reading Further Reading

Slide 33

Slide 33 text

Clojure Clojure Clojure o cial site 日本語版 Clojure の世界と実際のWeb 開発 Clojure の世界観 Clojure でREPL 駆動開発を始めよう Spectacular Future with clojure.spec

Slide 34

Slide 34 text

ClojureScript ClojureScript ClojureScript o cial site

Slide 35

Slide 35 text

Reagent/re-frame Reagent/re-frame cf. Reagent Guide to Reagent re-frame Re-frame: The Guide to Building Blocks ClojureScript & Reagent でReact 入門してみた ClojureScript/re-frame 開発における思考フロー Elm 開発における思考フロー