ClojureScript: The Good Parts

131 Views

June 26, 18

スライド概要

profile-image

「楽しく楽にcoolにsmartに」を理想とするprogrammer/philosopher/liberalist/realist。 好きな言語はClojure, Haskell, Python, English, français, русский。 読書、プログラミング、語学、法学、数学が大好き! イルカと海も大好き🐬

シェア

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

ClojureScript The Good Parts

2.

lagénorhynque カマイルカ /laʒenɔʁɛk ̃ / (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])

3.

Lisp × JavaScript

4.

What is ClojureScript?

5.

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

7.
[beta]
Try CLJS with 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

8.

Good Parts

9.

Lisp

10.

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

11.
[beta]
Collection Literals
cljs.user=> '(1 2 3)
(1 2 3)

; list

cljs.user=> [1 2 3]
[1 2 3]

; vector

cljs.user=> #{1 2 3}
#{1 2 3}

; set

cljs.user=> {:a 1 :b 2 :c 3}
{:a 1, :b 2, :c 3}

; map

cf. function de nition
(defn hello [& {:keys [to]
:or {to "world"}}]
(println (str "Hello, " to "!")))

12.

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

13.
[beta]
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]

14.

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

15.

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

17.

browser REPL for front-end development

18.

Changes are automatically loaded in the browser

19.

Functional Programming

20.
[beta]
Immutable Persistent
Collections
no mutations, no side e ects
high performance
ljs.user=> (conj [1 2] 3)
[1 2 3]

; add an element to vector

cljs.user=> (conj '(1 2) 3)
(3 1 2)

; add an element to list

cljs.user=> (conj #{1 2} 3)
#{1 2 3}

; add an element to set

cljs.user=> (assoc {:a 1 :b 2} :c 3)
{:a 1, :b 2, :c 3}

; add an entry to map

21.

Map and Sequence 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

22.
[beta]
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

23.

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

24.

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

25.

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

26.
[beta]
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

27.

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

28.

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

29.
[beta]
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
,,,

30.
[beta]
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
,,,

31.

Land of Lisp invades JS world!!

32.

Further Reading

34.

ClojureScript ClojureScript o cial site

35.

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