Practical REPL-driven Development with Clojure

462 Views

October 13, 17

スライド概要

Enjoy REPL-driven development with Clojure! (*> ᴗ •*)ゞ

profile-image

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

シェア

またはPlayer版

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

関連スライド

各ページのテキスト
1.

Practical REPL-driven Development with Clojure

2.

Self-introduction 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.

Contents 1. Clojure Quick Intro 2. Leiningen 3. Clojure REPL 4. Lisp Editing 5. REPL-driven Development in Practice

4.

Clojure Quick Intro

5.

Clojure Lisp S-expressions, macros, etc. REPL-driven development functional programming language dynamic language JVM language (cf. ClojureScript) ⇒ simple and powerful language

6.

literals type example string "abc" character \a number 1, 2.0, 3N, 4.5M, 6/7, 8r10 boolean true, false nil nil keyword :a, :user/a, ::a, ::x/a symbol 'a, 'user/a, `a, `x/a

7.

type example list '(1 2 3), '(+ 1 2 3) vector [1 2 3] set #{1 2 3} map {:a 1 :b 2}, #:user{:a 1 :b 2}, #::{:a 1 :b 2}, #::x{:a 1 :b 2} function (fn [x] (* x x))

8.

the syntax (op arg1 arg2 ... argn) operator function macro special form

9.

Leiningen

10.

lein repl starts Clojure REPL $ lein repl nREPL server started on port 49482 on host 127.0.0.1 - nrepl://1 27.0.0.1:49482 REPL-y 0.3.7, nREPL 0.2.12 Clojure 1.8.0 Java HotSpot(TM) 64-Bit Server VM 1.8.0_121-b13 Docs: (doc function-name-here) (find-doc "part-of-name-here") Source: (source function-name-here) Javadoc: (javadoc java-object-or-class-here) Exit: Control+D or (exit) or (quit) Results: Stored in vars *1, *2, *3, an exception in *e user=>

11.

lein new generates a new Clojure project $ lein new app clj-demo Generating a project called clj-demo based on the 'app' template generate a project with app template cf. lein-template

12.

$ tree clj-demo/ clj-demo/ ├── CHANGELOG.md ├── LICENSE ├── README.md ├── doc │ └── intro.md ├── project.clj ├── resources ├── src │ └── clj_demo │ └── core.clj └── test └── clj_demo └── core_test.clj

13.

lein run runs -main function $ cd clj-demo/ $ lein run Hello, World!

14.
[beta]
cf. src/clj_demo/core.clj
(ns clj-demo.core
(:gen-class))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "Hello, World!"))

15.

lein test runs tests $ lein test lein test clj-demo.core-test lein test :only clj-demo.core-test/a-test FAIL in (a-test) (core_test.clj:7) FIXME, I fail. expected: (= 0 1) actual: (not (= 0 1)) Ran 1 tests containing 1 assertions. 1 failures, 0 errors. Tests failed.

16.

cf. test/clj_demo/core_test.clj (ns clj-demo.core-test (:require [clojure.test :refer :all] [clj-demo.core :refer :all])) (deftest a-test (testing "FIXME, I fail." (is (= 0 1))))

17.

lein uberjar creates jar files $ lein uberjar Compiling clj-demo.core Created /Users/k.ohashi/code/clj-demo/target/uberjar/clj-demo-0. 1.0-SNAPSHOT.jar Created /Users/k.ohashi/code/clj-demo/target/uberjar/clj-demo-0. 1.0-SNAPSHOT-standalone.jar $ java -jar target/uberjar/clj-demo-0.1.0-SNAPSHOT-standalone.ja r Hello, World!

18.

Clojure REPL

19.

evaluate expressions clj-demo.core=> (map inc [0 1 2]) (1 2 3) clj-demo.core=> (println (map inc [0 1 2])) (1 2 3) nil

20.

clojure.repl/doc prints documentation clj-demo.core=> (doc map) ------------------------clojure.core/map ([f] [f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls]) Returns a lazy sequence consisting of the result of applying f to the set of first items of each coll, followed by applying f to the set of second items in each coll, until any one of the colls is exhausted. Any remaining items in other colls are ignored. Function f should accept number-of-colls arguments. Returns a transducer when no collection is provided. nil

21.
[beta]
clojure.repl/source
prints source code
clj-demo.core=> (source map)
(defn map
"Returns a lazy sequence consisting of the result of applying f to
the set of first items of each coll, followed by applying f to the
set of second items in each coll, until any one of the colls is
exhausted. Any remaining items in other colls are ignored. Function
f should accept number-of-colls arguments. Returns a transducer when
no collection is provided."
{:added "1.0"
:static true}
([f]
(fn [rf]
(fn
([] (rf))
([result] (rf result))
([result input]
(rf result (f input)))
([result input & inputs]
(rf result (apply f input inputs))))))

22.

clojure.core/*1, *2, *3 special vars bound to the most recent values printed clj-demo.core=> 21 21 clj-demo.core=> 2 2 clj-demo.core=> (* *2 *1) 42

23.
[beta]
clojure.core/*e
special var bound to the most recent exception
caught by the REPL
clj-demo.core=> (+ 1 "2")

ClassCastException java.lang.String cannot be cast to java.lang.Number
clj-demo.core=> *e
#error {
:cause "java.lang.String cannot be cast to java.lang.Number"
:via
[{:type java.lang.ClassCastException
:message "java.lang.String cannot be cast to java.lang.Number"
:at [clojure.lang.Numbers add "Numbers.java" 128]}]
:trace
[[clojure.lang.Numbers add "Numbers.java" 128]
[clojure.lang.Numbers add "Numbers.java" 3640]
[clj_demo.core$eval1328 invokeStatic "form-init3161334546666357405.cl
[clj_demo.core$eval1328 invoke "form-init3161334546666357405.clj" 1]
[clojure.lang.Compiler eval "Compiler.java" 6927]
[clojure.lang.Compiler eval "Compiler.java" 6890]
[clojure.core$eval invokeStatic "core.clj" 3105]

24.

search documentation clojure.repl/find-doc clojure.repl/apropos clojure.java.javadoc/javadoc

25.

Lisp editing

27.

Parinfer automatically adjust parentheses when editing indentation (Indent mode), indentation when editing parentheses (Paren mode)

28.

e.g. Atom with Parinfer

30.

defn␣my-map␣ [ f␣coll

31.

⌘-<RET> <TAB>

33.

when-let␣ [ s␣ ( seq␣coll

34.

⌘-<RET> <TAB>

36.

cons␣ ( f␣ ( first␣s

37.

⌘-<RET> <TAB> <TAB>

39.

my-map␣f␣ ( rest␣s

40.

<up> <up> ⌘-<left>

42.

lazy-seq <RET>

43.

<down> <TAB> <down> <TAB>

44.

ParEdit semi-automatically adjust parentheses and indentation cf. Smartparens

45.

e.g. Emacs with ParEdit

47.

defn␣my-map␣ [ f␣coll

49.

<RET>

51.

when-let␣ [ s␣ ( seq␣coll

52.

) )

53.

<RET> (

54.

cons␣ ( f␣ ( first␣s

55.

) )

56.

<RET>

57.

( my-map␣f␣ ( rest␣s

58.

<C>-<M>-u <C>-<M>-u <C>-<M>-u <C>-<M>-u

59.

<M>-(

60.

lazy-seq <RET>

61.

REPL-driven Development in Practice

62.

Course A: Clojure Koans Course B: 4Clojure

63.

Clojure Koans cf. ClojureScript Koans

64.

Clone the repository $ git clone git://github.com/functional-koans/clojure-koans.git Cloning into 'clojure-koans'... remote: Counting objects: 1590, done. remote: Compressing objects: 100% (7/7), done. remote: Total 1590 (delta 2), reused 4 (delta 1), pack-reused 15 80 Receiving objects: 100% (1590/1590), 269.87 KiB | 651.00 KiB/s, done. Resolving deltas: 100% (755/755), done.

65.
[beta]
Run koans
$ cd clojure-koans/
$ lein koan run
Starting auto-runner...
Considering /Users/k.ohashi/code/clojure-koans/src/koans/01_equa
lities.clj...
Now meditate upon /Users/k.ohashi/code/clojure-koans/src/koans/0
1_equalities.clj
--------------------Assertion failed!
clojure.lang.ExceptionInfo: We shall contemplate truth by testin
g reality, via equality
(= __ true) {:line 6}, compiling:(/Users/k.ohashi/code/clojure-k
oans/src/koans/01_equalities.clj:4:1)

66.

Open a source le with your favourite editor $ emacs src/koans/01_equalities.clj

67.

Start Clojure REPL

68.

Evaluate S-expressions

71.

Send S-expressions to REPL

77.
[beta]
Save changes and check the meditation result
...
Now meditate upon /Users/k.ohashi/code/clojure-koans/src/koans/0
1_equalities.clj
--------------------Assertion failed!
clojure.lang.ExceptionInfo: You can test equality of many things
(= (+ 3 4) 7 (+ 2 __)) {:line 12}, compiling:(/Users/k.ohashi/co
de/clojure-koans/src/koans/01_equalities.clj:4:1)

78.

4Clojure

79.

Open a new buffer with your favourite editor $ emacs clj-demo/src/clj_demo/4clojure/problem22.clj

80.

Start Clojure REPL

81.

e.g. Problem #22 Count a Sequence Write a function which returns the total number of elements in a sequence. (= (= (= (= (= (__ (__ (__ (__ (__ '(1 2 3 3 1)) 5) "Hello World") 11) [[1 2] [3 4] [5 6]]) 3) '(13)) 1) '(:a :b :c)) 3) Special Restrictions: count

82.

Write a function

83.

Evaluate S-expressions

89.

Send S-expressions to REPL

96.

Run your solution on the problem page (fn my-count [coll] (reduce (fn [n _] (inc n)) 0 coll))

97.

Enjoy REPL-driven development!

98.

Further Reading

99.

Clojure & ClojureScript Clojure ClojureScript build tool Leiningen

100.

editor plugins/settings Clojure develompent Emacs CIDER Clojure 初⼼者のための Emacs 設定作りました 新: Emacs を使うモダンな Clojure 開発環境 cf. Spacemacs Clojure layer Clojure development with Spacemacs & Cider

101.

IntelliJ IDEA Cursive IntelliJ IDEA と Cursive で始める — Clojure の⽇ 本語ガイド Atom Atom Clojure Setup ClojureやりたいけどEmacsは厳しい⼈のための proto-repl⼊⾨

104.

REPL-driven development Re:REPL-Driven Development REPL Driven Development REPL Driven Development and Testing in Clojure