Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ClojureScript: The Good Parts

ClojureScript: The Good Parts

Kent OHASHI

June 26, 2018
Tweet

More Decks by Kent OHASHI

Other Decks in Programming

Transcript

  1. カマイルカ /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])
  2. (CLJS) (CLJS) compiler for Clojure that targets JavaScript cf. (JVM/Java),

    (CLR/C#) simple and powerful functional Lisp ClojureScript ClojureScript Clojure ClojureCLR
  3. Use Cases Use Cases SPA: / , , , etc.

    React Native: Electron Node.js AWS Lambda etc. Reagent re-frame Rum Om re-natal
  4. 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
  5. S-expressions (sexp) S-expressions (sexp) simple rule: (op arg ...) various

    kinds of functions macros special forms structural editing , , etc. ParEdit Parinfer
  6. 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 "!")))
  7. 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]
  8. 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
  9. 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}
  10. 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
  11. 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
  12. 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
  13. Data > Functions > Macros Data > Functions > Macros

    data-driven/oriented design examples libraries: , , frameworks: , , Honey SQL Hiccup Reagent Duct Pedestal re-frame
  14. speci cation system similar to Racket's cf. gradual typing e.g.

    (Typed Clojure) clojure.spec clojure.spec contract system core.typed
  15. 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
  16. 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
  17. 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
  18. 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 ,,,
  19. 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 ,,,
  20. Clojure Clojure Clojure o cial site 日本語版 Clojure の世界と実際のWeb 開発

    Clojure の世界観 Clojure でREPL 駆動開発を始めよう Spectacular Future with clojure.spec
  21. 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 開発における思考フロー