SlideShare une entreprise Scribd logo
1  sur  33
Clojure
Programming
        reading (※お菓子会)
(CHAPTER 2. Functional Programming)
           2012/07/28 @ponkore



                    1
自己紹介
•   @ponkore
•   職業:とあるSIerのSE

•   業務では最近コード書いてません(どちらかというと管理する側)

    •   Excel方眼紙でドキュメント、Excel&VBAで進 ・品質管理... orz

    •   Java, C#,VB.Net とかが多い

•   Lispやりてぇ→何か無いかな→Java, Lispでぐぐる

    →Clojure発見(2011年秋)

    →2012/04/22 kyoto.clj 顔出し(この時は聞くだけでした...)

    → 今日はなんとか発表(今ここ)


                                2
はじめに
•   大きな「節」単位で整理してみました。

•   それなりに端折ります(細かいところまで完全には読み込
    めていません)。

•   本の中で出てきているコードはなるべく引用しています。

    •   Preface|xvii ページ “Using Code Examples”によると作者に
        contactをする必要もなさそうなので。

•   ツッコミ、誤りのご指摘、補足は大歓迎です。


                           3
Chapter 2. Functional Programming

 •   この章で書いてある内容(ざっくり)

     •   (Immutable な)値の重要性

     •   高階関数(Higher Order Function:HOF)

     •   関数の部分適用

     •   関数の合成(Composition)

     •   Logging System を作ってみよう

     •   純関数(Pure Functions)とメモ化とか


                           4
What does Functional
Programming Mean?
•   「関数型プログラミング」→いろんな言語
    で定義はまちまち(少しあいまいな概念)

•   Clojure 的には...

    -   immutableなデータ構造

    -   高階関数(higher-order-functions)

    -   関数合成、等々

                        5
On the Importance of
Values(1)
• About Values
   - JVM標準のBoolean、Number、
    Character、String、といった型は、
    Clojureでは immutable な値として利用
    できるようにしている(安心して使っ
    てよし!)

               6
On the Importance of
Values(2)
  • Clojure では以下の比較式はすべてtrue
        (= 5 5)
        (= 5 (+ 2 3))
        (= "boot" (str "bo" "ot"))               ;   下記Memo 参照


        (= nil nil)
        (let [a 5]
         (do-something-with-a-number a)
         (= a 5))

Memo: Clojure における ‘=’ は、imutable な’値’に対して比較。javaの == とはちょっと違う。
clojure.core/=
([x] [x y] [x y & more])
  Equality. Returns true if x equals y, false if not. Same as
  Java x.equals(y) except it also works for nil, and compares
  numbers and collections in a type-independent manner. Clojure's immutable data
  structures define equals() (and thus =) as a value, not an identity,
  comparison.

                                         7
On the Importance of
Values(3)
 • Comparing Values to Mutable Objects
        Mutable Object の例(StatefulInteger class)
public class StatefulInteger extends Number {
 private int state;
 public StatefulInteger (int initialState) {
  this.state = initialState; }
 public void setInt (int newState) { this.state = newState; }
 public int intValue () { return state; }
 public int hashCode () { return state; }
 public boolean equals (Object obj) {
    return obj instanceof StatefulInteger &&
     state == ((StatefulInteger)obj).state;
 }}




                               8
On the Importance of
Values(4)
•   (ちょっと横道)

    StatefulInteger クラスを Java で書くと、クラスパスを通し
    たりなにかとめんどい。ので、Clojure で書いてみた。
    ;;; gist に上げてあります       https://gist.github.com/3162439
    (defprotocol IStatefulInteger
      (setInt [this new-state])
      (intValue [this]))

    (deftype StatefulInteger [^{:volatile-mutable true} state]
      IStatefulInteger
      (setInt [this new-state] (set! state new-state))
      (intValue [this] state)
      Object
      (hashCode [this] state)
      (equals [this obj]
        (and (instance? (class this) obj)
             (= state (.intValue obj)))))
                                    9
On the Importance of
  Values(5)
   • StatefulInteger をClojure からいじってみる
(def five (StatefulInteger. 5))
;= #'user/five
(def six (StatefulInteger. 6))
;= #'user/six
(.intValue five)
;= 5
(= five six)                      fiveは“5”のつもり
;= false                           なのに“6”に
(.setInt five 6)
                                  なってしまった
;= nil
(= five six)
;= true



                             10
On the Importance of
 Values(6)
   • StatefulInteger をさらに邪悪にいじる
(defn print-number           ※前ページの続き:five=6, six=6
 [n]
 (println (.intValue n))
 (.setInt n 42))           ; printlnした後に値を42に変更!
;= #'user/print-number
(print-number six)
; 6
;= nil
(= five six)
;= false     ※前ページの結果はtrue→状態が変わった!

(= five (StatefulInteger. 42)) ;P.56の例ではfiveだがsixの誤りでは?
;= true


                             11
On the Importance of
Values(7)
• Ruby は String でさえ Mutable
  >>   s= "hello"
  =>   "hello"
  >>   s << "*"
  =>   "hello*"
  >>   s == "hello"
  =>   false
 ただし.freezeを使えば不用意な変更は阻止できる
  >> s.freeze
  => "hello*"
  >> s << "*"
  RuntimeError: can't modify frozen String
      from (irb):4
      from /opt/local/bin/irb:12:in `<main>'


                         12
On the Importance of
Values(8)
• Ruby は Hash の key でさえ変更可能
 >>   h = {[1, 2] => 3} # [1,2]というキーをもつHash hを作る
 =>   {[1, 2]=>3}
 >>   h[[1,2]]
 =>   3
 >>   h.keys
 =>   [[1, 2]]
 >>   h.keys[0]
 =>   [1, 2]
 >>   h.keys[0] << 3
 =>   [1, 2, 3]      # h.keys[0]はもともと[1,2]だった

 >>   h[[1,2]]       # [1,2]にhitする値はもうhには無い

 =>   nil            ※h.keys[0].freeze で keys[0]を保護できなくはない




                             13
On the Importance of
Values(9)
• Clojureのmapのkeyは変更不可
 (def h {[1, 2] 3})
 ;= #'user/h
 (h [1 2])
 ;= 3
 (conj (first (keys h)) 3)
 ;= [1 2 3]                  ※h のkey [1 2] が変更
 (h [1 2])                   されたわけではない
 ;= 3              元のまま
 h
 ;= {[1 2] 3}




                        14
On the Importance of
Values(10)
•       A Critical Choice
    •    “自由に変更可能な状態を持つ”(Mutable な)オブジェクトを使
         えてしまうと...

        ◦ Mutableなオブジェクトは、安全にメソッドに渡せない
        ◦ Mutableなオブジェクトは、hashのkeyやsetのentryとかには安心して使え
         ない
        ◦ Mutableなオブジェクトは、安全にキャッシュできない(キーが変更されうる)
        ◦ Mutableなオブジェクトは、マルチスレッド環境では安心して使えない(ス
         レッド間で正しく同期させる必要がある)

        ◦ 色々理由はあるけど、今後のことを考えてMutableなオブジェクトはなるべ
         く使わない方向にしたよ、ということ。

                             15
First-Class and Higher
Order-Functions(1)
  • 関数型プログラミングの特徴(要件)
    ◦ 関数自身を値として他のデータと同様に取り扱える
     =関数を引数や戻り値として取り扱える


  • 例:call_twice
# Ruby                              # Python
def call_twice(x, &f)               def call_twice(f, x):
  f.call(x)                           f(x)
  f.call(x)                           f(x)
end
                                    call_twice(print, 123)
call_twice(123) {|x| puts x}

                               16
First-Class and Higher
Order-Functions(2)
• Clojure では...   まあ普通な感じ




        ;Clojure
        (defn call-twice [f x]
          (f x)
          (f x))

        (call-twice println 123)




                     17
First-Class and Higher
    Order-Functions(3)
      •   map (clojure.core/map)

(map clojure.string/lower-case [“Java” “Imperative” “Weeping”
                                “Clojure” “Learning” “Peace”])
;= (“java” “imperative” “weeping” “clojure” “learning” “peace”)


(map * [1 2 3 4] [5 6 7 8])   ;collection が複数ある場合
;= (5 12 21 32)
;中身としては (map #(* % %2) [1 2 3 4] [5 6 7 8])

(map * [1 2 3] [4 5 6 7] [8 9 10 11 12])
;= (32 90 180)    ;※要素の数は少ない方に合わせられる
;中身としては (map #(* % %2 %3) [1 2 3] [4 5 6 7] [8 9 10 11 12])


                                18
First-Class and Higher
Order-Functions(4)
•   reduce (clojure.core/reduce)
      (reduce max [0 -3 10 48])

          (max 0 -3)
          ;= 0
          (max 0 10)
          ;= 10
          (max 10 48)
          ;= 48
      ;= 48     (のはず P.63   には 10と書いてある...)


      (max (max (max 0 -3) 10) 48)
      ;= 48

      ;あるいは以下のようも書ける
      (reduce #(max % %2) [0 -3 10 48])
                                19
First-Class and Higher
   Order-Functions(5)
   •
(reduce
       reduce (clojure.core/reduce) 続き
 (fn [m v]                              ; (fn []... ) anonymous function
    (assoc m v (* v v)))
 {}
 [1 2 3 4])
 ;(assoc   {}   1 (* 1 1))              =>   {1   1}
 ;(assoc   {1   1} 2 (* 2 2))           =>   {2   4,1 1}
 ;(assoc   {2   4,1 1} 3 (* 3 3))       =>   {3   9,1 1,2 4}
 ;(assoc   {3   9,1 1,2 4} 4 (* 4 4))   =>   {4   16,1 1,2 4,3 9}
;= {4 16, 3 9, 2 4, 1 1}

;あるいは以下のようも書ける
(reduce
 #(assoc % %2 (* %2 %2)))               ; #(...) function literal
 {}
 [1 2 3 4])

                                                  20
First-Class and Higher
    Order-Functions(6)
    •   Applying Ourselves Partially (関数部分適用の話)
(def only-strings (partial filter string?))
;= #’user/only-strings

(only-strings [“a” 5 “b” 6])
;= (“a” “b”)

;ところで only-strings の正体って何?
only-strings
;= #<core$partial$fn__3794   clojure.core$partial$fn__3794@5719510f>
;関数っぽい

(class only-strings)
;= user$only_strings         ;だそうで...




                                         21
First-Class and Higher
     Order-Functions(7)
     •   Applying Ourselves Partially (関数部分適用の話)
partial versus function literals.

 ; only-strings 相当のことを関数リテラルでやってみる
 (#(filter string? %) [“a” 5 “b” 6])
 ;= (“a” “b”)     ; できた!簡単!

 ;filter の述語を置き換える、なんてことも...
 (#(filter % [“a” 5 “b” 6]) string?)
 ;= (“a” “b”)
 (#(filter % [“a” 5 “b” 6]) number?)
 ;= (5 6)

 ;partial じゃなく関数リテラルだけでもいいんじゃ?....
 ; => partial の場合、引数を厳密に指定しなくてもよい場合 にすっきり見える
     (次ページ)                     22
First-Class and Higher
  Order-Functions(8)
   •   Applying Ourselves Partially (関数部分適用の話)
partial versus function literals. (続き)
 ;まずは関数リテラル
 (#(map *) [1 2 3] [4 5 6] [7 8 9])
 ;= ArityException Wrong number of args (3) passed ...
 (#(map * % %2 %3) [1 2 3] [4 5 6] [7 8 9])
 ;= (28 80 162)
 (#(map * % %2 %3) [1 2 3] [4 5 6])
 ;= ArityException Wrong number of args (2) passed ...
 (#(apply map * %&) [1 2 3] [4 5 6] [7 8 9])
 ;= (28 80 162)
 (#(apply map * %&) [1 2 3])
 ;= (1 2 3)      ; %& で引数の数は気にしなくて良くなったが apply           がうっとおしい...
 ;次に partial の出番
 ((partial map *) [1 2 3] [4 5 6] [7 8 9])
 ;= (28 80 162)
 ((partial map *) [1 2 3])
 ;= (1 2 3)                   23
Composition of
Function(ality)(1)
•   Composition って何?
    (defn negated-sum-str
      [& numbers]                                           10    12     3.4
      (str (- (apply + numbers))))
    ;= #’user/negated-num-str
    (negated-sum-str 10 12 3.4)                                    +
    ;= “-25.4”
                                                                 25.4
    (def negated-sum-str (comp str - +))                           -
    ;= #’user/negated-num-str
    ;※関数を返してくれる!                                                 -25.4
    ;しかもpartial同様引数の個数とか気にしない!
                                                                  str
    (negated-sum-str 10 12 3.4)
    ;= “-25.4”
                                                             “-25.4”
     ※P71.脚注26 “point-free   style” (引数を明示的に指定・参照しないスタイル)

                                          24
Composition of
Function(ality)(2)
•   Composition もう一つの例(camel->keyword)
(require '[clojure.string :as str])
(def camel->keyword (comp keyword
                          str/join
                          (partial interpose -)
                          (partial map str/lower-case)
                          #(str/split % #"(?<=[a-z])(?=[A-Z])")))

;= #'user/camel->keyword
(camel->keyword "CamelCase")
;= :camel-case
(camel->keyword "lowerCamelCase")
;= :lower-camel-case


;; 上記場面では、以下のように ->> を使うこともできる(こっちのほうが多いかな?)
;; ※comp とは順番が異なることに注意。またcompで必要だった partial   等も不要。
(defn camel->keyword
  [s]
  (->> (str/split % #"(?<=[a-z])(?=[A-Z])")
        (map str/lower-case)
        (interpose -)
        str/join
        keyword))                    25
Composition of
 Function(ality)(3)
  •   camel->keywordを応用してみる(camel-pairs->map)
(def camel-pairs->map (comp (partial apply hash-map)
                            (partial map-indexed (fn [i x]
                                                   (if (odd? i)
                                                     x
                                                     (camel->keyword x))))))

;= #'user/camel-pairs->map

(camel-pairs->map ["CamelCase" 5 "lowerCamelCase" 3])
;= {:camel-case 5, :lower-camel-case 3}




                                      26
Composition of
 Function(ality)(4)
 •   Writing Higher-Order Functions
;お約束の adder
(defn adder                  ; 「関数」を戻り値として返す

  [n]
  (fn [x] (+ n x)))
;= #'user/adder
((adder 5) 18)
;= 23
(defn doubler                ; 関数をパラメータとして渡す

  [f]
  (fn [& args]
    (* 2 (apply f args))))
;= #'user/doubler
(def double-+ (doubler +))
;= #'user/doubler-+
(double-+ 1 2 3)             ; Clojureの+はいくつでも引数を取れる。便利。

;= 12                         27
Composition of
 Function(ality)(5)
  •     Building a Primitive Logging System with Composable Higher-Order
        Functions
       •     高階関数を使ってログ出力をいろいろ作ってみる。

      print-logger          パラメータwriterを出力先に指定できる関数を返す。
      *out-logger*          print-logger をつかった、*out* に出力する関数。
      retained-logger       print-logger をつかった、StringWriter に出力する関数。
      file-logger            パラメータfileを出力先に指定できる関数を返す。
      log->file              “message.log”というファイルに出力する関数。
      multi-logger          logger関数を複数順番に呼び出す(doseq)関数を返す。
      log                   multi-loggerを使って、*out*と”message.log”に出力する関数。
      timestamped-logger    ログメッセージに日時を付加する関数を返す。
      log-timestamped       今までの集大成。

コードは長いのでスライド上は省略します。gist に貼ってありますので、そちらをご参照願います。
https://gist.github.com/3173902/

                                         28
Pure Functions
•   Pure Functionって何?

    •   「副作用」(side effects)のない関数、のこと

    •   じゃあ「副作用のある関数」って何?

        1. ランダムな状態に依存(乱数を使ってる、とか)

        2. 1回めの呼び出しと次回以降の呼び出しで結果が変わる

         ※I/Oを実行する関数は副作用あり。

         (P.77 では @ClojureBook のフォロワー数の出力を例示

          →呼び出したタイミングにより値が変わる)


                         29
Pure Functions
•   Why Are Pure Functions Interesting?
    •   Pure functions are easier to reason about.
        •   入力パラメータが決まれば出力は必ず同じ出力になる。

    •   Pure functions are easier to test.

        •   (関数を実行する時点の)状態を考える必要がないのでテストしやすい。

    •   Pure functions are cacheable and trivial to parallelize.

        •   入力パラメータが決まれば出力は必ず同じー>入力パラメータに対応し
            た出力結果をキャッシュ(メモ化)することで、2回目以降の呼び出しを
            高速化できる。

            (次ページにメモ化の例)




                                             30
Pure Functions
       •   メモ化の例(素数判定)
(defn prime?
  [n]
  (cond
   (== 1 n) false
   (== 2 n) true
   (even? n) false
   :else (->> (range 3 (inc (Math/sqrt n)) 2)
              (filter #(zero? (rem n %)))
              empty?)))
(time (prime? 1125899906842679))
; "Elapsed time: 2181.014 msecs"
;= true

(let [m-prime? (memoize prime?)]   ; memoize:「関数をメモ化した関数」を返す。
  (time (m-prime? 1125899906842679))
  (time (m-prime? 1125899906842679)))
; "Elapsed time: 2085.029 msecs"
; "Elapsed time: 0.042 msecs"

                                   31
Functional Programming
in the Real World
       Functional
      Programming
         in the
       Real World



                    メリット
                    •予測しやすいコード
                    •テストの容易さ
                    •再利用の容易さ

             32
ご清聴ありがとうございました。




       33

Contenu connexe

Tendances

Java電卓勉強会資料
Java電卓勉強会資料Java電卓勉強会資料
Java電卓勉強会資料
Toshio Ehara
 
並行プログラミングと継続モナド
並行プログラミングと継続モナド並行プログラミングと継続モナド
並行プログラミングと継続モナド
Kousuke Ruichi
 
Scalaで萌える関数型プログラミング[1.1.RC1]
Scalaで萌える関数型プログラミング[1.1.RC1]Scalaで萌える関数型プログラミング[1.1.RC1]
Scalaで萌える関数型プログラミング[1.1.RC1]
Ra Zon
 
C++11概要 ライブラリ編
C++11概要 ライブラリ編C++11概要 ライブラリ編
C++11概要 ライブラリ編
egtra
 

Tendances (20)

Material
MaterialMaterial
Material
 
C++0x 言語の未来を語る
C++0x 言語の未来を語るC++0x 言語の未来を語る
C++0x 言語の未来を語る
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
C#を始めたばかりの人へのLINQ to Objects
C#を始めたばかりの人へのLINQ to ObjectsC#を始めたばかりの人へのLINQ to Objects
C#を始めたばかりの人へのLINQ to Objects
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14
 
Java電卓勉強会資料
Java電卓勉強会資料Java電卓勉強会資料
Java電卓勉強会資料
 
C#6.0の新機能紹介
C#6.0の新機能紹介C#6.0の新機能紹介
C#6.0の新機能紹介
 
Java初心者勉強会(2015/08/07)資料
Java初心者勉強会(2015/08/07)資料Java初心者勉強会(2015/08/07)資料
Java初心者勉強会(2015/08/07)資料
 
C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜
C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜
C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜
 
並行プログラミングと継続モナド
並行プログラミングと継続モナド並行プログラミングと継続モナド
並行プログラミングと継続モナド
 
Bluespec @waseda(PDF)
Bluespec @waseda(PDF)Bluespec @waseda(PDF)
Bluespec @waseda(PDF)
 
Frege, What a Non-strict Language
Frege, What a Non-strict LanguageFrege, What a Non-strict Language
Frege, What a Non-strict Language
 
PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門
 
Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術
 
函数プログラミングの エッセンスと考え方
函数プログラミングのエッセンスと考え方函数プログラミングのエッセンスと考え方
函数プログラミングの エッセンスと考え方
 
クロージャデザインパターン
クロージャデザインパターンクロージャデザインパターン
クロージャデザインパターン
 
Scalaで萌える関数型プログラミング[1.1.RC1]
Scalaで萌える関数型プログラミング[1.1.RC1]Scalaで萌える関数型プログラミング[1.1.RC1]
Scalaで萌える関数型プログラミング[1.1.RC1]
 
C++11概要 ライブラリ編
C++11概要 ライブラリ編C++11概要 ライブラリ編
C++11概要 ライブラリ編
 
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
 

En vedette (6)

Practical Clojure Programming
Practical Clojure ProgrammingPractical Clojure Programming
Practical Clojure Programming
 
Clojure Intro
Clojure IntroClojure Intro
Clojure Intro
 
Clojure A Dynamic Programming Language for the JVM
Clojure A Dynamic Programming Language for the JVMClojure A Dynamic Programming Language for the JVM
Clojure A Dynamic Programming Language for the JVM
 
我的奇幻漂流日記
我的奇幻漂流日記我的奇幻漂流日記
我的奇幻漂流日記
 
Functional web development with Git(Hub), Heroku and Clojure
Functional web development with Git(Hub), Heroku and ClojureFunctional web development with Git(Hub), Heroku and Clojure
Functional web development with Git(Hub), Heroku and Clojure
 
Clojure - An Introduction for Java Programmers
Clojure - An Introduction for Java ProgrammersClojure - An Introduction for Java Programmers
Clojure - An Introduction for Java Programmers
 

Similaire à Clojure programming-chapter-2

Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]
Ra Zon
 
Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2
Ransui Iso
 
Unity2015_No10_~UGUI&Audio~
Unity2015_No10_~UGUI&Audio~Unity2015_No10_~UGUI&Audio~
Unity2015_No10_~UGUI&Audio~
CHY72
 
知って得するC#
知って得するC#知って得するC#
知って得するC#
Shota Baba
 
初心者講習会資料(Osaka.R#5)
初心者講習会資料(Osaka.R#5)初心者講習会資料(Osaka.R#5)
初心者講習会資料(Osaka.R#5)
Masahiro Hayashi
 
12-11-30 Kashiwa.R #5 初めてのR Rを始める前に知っておきたい10のこと
12-11-30 Kashiwa.R #5 初めてのR Rを始める前に知っておきたい10のこと 12-11-30 Kashiwa.R #5 初めてのR Rを始める前に知っておきたい10のこと
12-11-30 Kashiwa.R #5 初めてのR Rを始める前に知っておきたい10のこと
Haruka Ozaki
 

Similaire à Clojure programming-chapter-2 (20)

Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
 
JavaScript 講習会 #1
JavaScript 講習会 #1JavaScript 講習会 #1
JavaScript 講習会 #1
 
eZ Publish勉強会9月〜テンプレート言語〜
eZ Publish勉強会9月〜テンプレート言語〜eZ Publish勉強会9月〜テンプレート言語〜
eZ Publish勉強会9月〜テンプレート言語〜
 
(Ruby使いのための)Scalaで学ぶ関数型プログラミング
(Ruby使いのための)Scalaで学ぶ関数型プログラミング(Ruby使いのための)Scalaで学ぶ関数型プログラミング
(Ruby使いのための)Scalaで学ぶ関数型プログラミング
 
秀スクリプトの話
秀スクリプトの話秀スクリプトの話
秀スクリプトの話
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~
 
Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]
 
X hago2 shortcoding 20110827
X hago2 shortcoding 20110827X hago2 shortcoding 20110827
X hago2 shortcoding 20110827
 
Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2
 
Unity2015_No10_~UGUI&Audio~
Unity2015_No10_~UGUI&Audio~Unity2015_No10_~UGUI&Audio~
Unity2015_No10_~UGUI&Audio~
 
知って得するC#
知って得するC#知って得するC#
知って得するC#
 
初心者講習会資料(Osaka.R#5)
初心者講習会資料(Osaka.R#5)初心者講習会資料(Osaka.R#5)
初心者講習会資料(Osaka.R#5)
 
Aizu lt tokyo_luxion
Aizu lt tokyo_luxionAizu lt tokyo_luxion
Aizu lt tokyo_luxion
 
JavaScript入門
JavaScript入門JavaScript入門
JavaScript入門
 
Gorinphp0729
Gorinphp0729Gorinphp0729
Gorinphp0729
 
Gorinphp0729
Gorinphp0729Gorinphp0729
Gorinphp0729
 
Objc lambda
Objc lambdaObjc lambda
Objc lambda
 
12-11-30 Kashiwa.R #5 初めてのR Rを始める前に知っておきたい10のこと
12-11-30 Kashiwa.R #5 初めてのR Rを始める前に知っておきたい10のこと 12-11-30 Kashiwa.R #5 初めてのR Rを始める前に知っておきたい10のこと
12-11-30 Kashiwa.R #5 初めてのR Rを始める前に知っておきたい10のこと
 
R language definition3.1_3.2
R language definition3.1_3.2R language definition3.1_3.2
R language definition3.1_3.2
 

Dernier

The_Five_Books_Overview_Presentation_2024
The_Five_Books_Overview_Presentation_2024The_Five_Books_Overview_Presentation_2024
The_Five_Books_Overview_Presentation_2024
koheioishi1
 
TokyoTechGraduateExaminationPresentation
TokyoTechGraduateExaminationPresentationTokyoTechGraduateExaminationPresentation
TokyoTechGraduateExaminationPresentation
YukiTerazawa
 

Dernier (8)

The_Five_Books_Overview_Presentation_2024
The_Five_Books_Overview_Presentation_2024The_Five_Books_Overview_Presentation_2024
The_Five_Books_Overview_Presentation_2024
 
TokyoTechGraduateExaminationPresentation
TokyoTechGraduateExaminationPresentationTokyoTechGraduateExaminationPresentation
TokyoTechGraduateExaminationPresentation
 
世界を変えるクレーンを生み出そう! 高知エンジニアリングキャンプ2024プログラム
世界を変えるクレーンを生み出そう! 高知エンジニアリングキャンプ2024プログラム世界を変えるクレーンを生み出そう! 高知エンジニアリングキャンプ2024プログラム
世界を変えるクレーンを生み出そう! 高知エンジニアリングキャンプ2024プログラム
 
2024年度 東京工業大学 工学院 機械系 大学院 修士課程 入試 説明会 資料
2024年度 東京工業大学 工学院 機械系 大学院 修士課程 入試 説明会 資料2024年度 東京工業大学 工学院 機械系 大学院 修士課程 入試 説明会 資料
2024年度 東京工業大学 工学院 機械系 大学院 修士課程 入試 説明会 資料
 
東京工業大学 環境・社会理工学院 建築学系 大学院入学入試・進学説明会2024_v2
東京工業大学 環境・社会理工学院 建築学系 大学院入学入試・進学説明会2024_v2東京工業大学 環境・社会理工学院 建築学系 大学院入学入試・進学説明会2024_v2
東京工業大学 環境・社会理工学院 建築学系 大学院入学入試・進学説明会2024_v2
 
生成AIの回答内容の修正を課題としたレポートについて:お茶の水女子大学「授業・研究における生成系AIの活用事例」での講演資料
生成AIの回答内容の修正を課題としたレポートについて:お茶の水女子大学「授業・研究における生成系AIの活用事例」での講演資料生成AIの回答内容の修正を課題としたレポートについて:お茶の水女子大学「授業・研究における生成系AIの活用事例」での講演資料
生成AIの回答内容の修正を課題としたレポートについて:お茶の水女子大学「授業・研究における生成系AIの活用事例」での講演資料
 
ゲーム理論 BASIC 演習106 -価格の交渉ゲーム-#ゲーム理論 #gametheory #数学
ゲーム理論 BASIC 演習106 -価格の交渉ゲーム-#ゲーム理論 #gametheory #数学ゲーム理論 BASIC 演習106 -価格の交渉ゲーム-#ゲーム理論 #gametheory #数学
ゲーム理論 BASIC 演習106 -価格の交渉ゲーム-#ゲーム理論 #gametheory #数学
 
次世代機の製品コンセプトを描く ~未来の機械を創造してみよう~
次世代機の製品コンセプトを描く ~未来の機械を創造してみよう~次世代機の製品コンセプトを描く ~未来の機械を創造してみよう~
次世代機の製品コンセプトを描く ~未来の機械を創造してみよう~
 

Clojure programming-chapter-2

  • 1. Clojure Programming reading (※お菓子会) (CHAPTER 2. Functional Programming) 2012/07/28 @ponkore 1
  • 2. 自己紹介 • @ponkore • 職業:とあるSIerのSE • 業務では最近コード書いてません(どちらかというと管理する側) • Excel方眼紙でドキュメント、Excel&VBAで進 ・品質管理... orz • Java, C#,VB.Net とかが多い • Lispやりてぇ→何か無いかな→Java, Lispでぐぐる →Clojure発見(2011年秋) →2012/04/22 kyoto.clj 顔出し(この時は聞くだけでした...) → 今日はなんとか発表(今ここ) 2
  • 3. はじめに • 大きな「節」単位で整理してみました。 • それなりに端折ります(細かいところまで完全には読み込 めていません)。 • 本の中で出てきているコードはなるべく引用しています。 • Preface|xvii ページ “Using Code Examples”によると作者に contactをする必要もなさそうなので。 • ツッコミ、誤りのご指摘、補足は大歓迎です。 3
  • 4. Chapter 2. Functional Programming • この章で書いてある内容(ざっくり) • (Immutable な)値の重要性 • 高階関数(Higher Order Function:HOF) • 関数の部分適用 • 関数の合成(Composition) • Logging System を作ってみよう • 純関数(Pure Functions)とメモ化とか 4
  • 5. What does Functional Programming Mean? • 「関数型プログラミング」→いろんな言語 で定義はまちまち(少しあいまいな概念) • Clojure 的には... - immutableなデータ構造 - 高階関数(higher-order-functions) - 関数合成、等々 5
  • 6. On the Importance of Values(1) • About Values - JVM標準のBoolean、Number、 Character、String、といった型は、 Clojureでは immutable な値として利用 できるようにしている(安心して使っ てよし!) 6
  • 7. On the Importance of Values(2) • Clojure では以下の比較式はすべてtrue (= 5 5) (= 5 (+ 2 3)) (= "boot" (str "bo" "ot")) ; 下記Memo 参照 (= nil nil) (let [a 5] (do-something-with-a-number a) (= a 5)) Memo: Clojure における ‘=’ は、imutable な’値’に対して比較。javaの == とはちょっと違う。 clojure.core/= ([x] [x y] [x y & more]) Equality. Returns true if x equals y, false if not. Same as Java x.equals(y) except it also works for nil, and compares numbers and collections in a type-independent manner. Clojure's immutable data structures define equals() (and thus =) as a value, not an identity, comparison. 7
  • 8. On the Importance of Values(3) • Comparing Values to Mutable Objects Mutable Object の例(StatefulInteger class) public class StatefulInteger extends Number { private int state; public StatefulInteger (int initialState) { this.state = initialState; } public void setInt (int newState) { this.state = newState; } public int intValue () { return state; } public int hashCode () { return state; } public boolean equals (Object obj) { return obj instanceof StatefulInteger && state == ((StatefulInteger)obj).state; }} 8
  • 9. On the Importance of Values(4) • (ちょっと横道) StatefulInteger クラスを Java で書くと、クラスパスを通し たりなにかとめんどい。ので、Clojure で書いてみた。 ;;; gist に上げてあります https://gist.github.com/3162439 (defprotocol IStatefulInteger   (setInt [this new-state])   (intValue [this])) (deftype StatefulInteger [^{:volatile-mutable true} state]   IStatefulInteger   (setInt [this new-state] (set! state new-state))   (intValue [this] state)   Object   (hashCode [this] state)   (equals [this obj]     (and (instance? (class this) obj)          (= state (.intValue obj))))) 9
  • 10. On the Importance of Values(5) • StatefulInteger をClojure からいじってみる (def five (StatefulInteger. 5)) ;= #'user/five (def six (StatefulInteger. 6)) ;= #'user/six (.intValue five) ;= 5 (= five six) fiveは“5”のつもり ;= false なのに“6”に (.setInt five 6) なってしまった ;= nil (= five six) ;= true 10
  • 11. On the Importance of Values(6) • StatefulInteger をさらに邪悪にいじる (defn print-number ※前ページの続き:five=6, six=6 [n] (println (.intValue n)) (.setInt n 42)) ; printlnした後に値を42に変更! ;= #'user/print-number (print-number six) ; 6 ;= nil (= five six) ;= false ※前ページの結果はtrue→状態が変わった! (= five (StatefulInteger. 42)) ;P.56の例ではfiveだがsixの誤りでは? ;= true 11
  • 12. On the Importance of Values(7) • Ruby は String でさえ Mutable >> s= "hello" => "hello" >> s << "*" => "hello*" >> s == "hello" => false ただし.freezeを使えば不用意な変更は阻止できる >> s.freeze => "hello*" >> s << "*" RuntimeError: can't modify frozen String from (irb):4 from /opt/local/bin/irb:12:in `<main>' 12
  • 13. On the Importance of Values(8) • Ruby は Hash の key でさえ変更可能 >> h = {[1, 2] => 3} # [1,2]というキーをもつHash hを作る => {[1, 2]=>3} >> h[[1,2]] => 3 >> h.keys => [[1, 2]] >> h.keys[0] => [1, 2] >> h.keys[0] << 3 => [1, 2, 3] # h.keys[0]はもともと[1,2]だった >> h[[1,2]] # [1,2]にhitする値はもうhには無い => nil ※h.keys[0].freeze で keys[0]を保護できなくはない 13
  • 14. On the Importance of Values(9) • Clojureのmapのkeyは変更不可 (def h {[1, 2] 3}) ;= #'user/h (h [1 2]) ;= 3 (conj (first (keys h)) 3) ;= [1 2 3] ※h のkey [1 2] が変更 (h [1 2]) されたわけではない ;= 3 元のまま h ;= {[1 2] 3} 14
  • 15. On the Importance of Values(10) • A Critical Choice • “自由に変更可能な状態を持つ”(Mutable な)オブジェクトを使 えてしまうと... ◦ Mutableなオブジェクトは、安全にメソッドに渡せない ◦ Mutableなオブジェクトは、hashのkeyやsetのentryとかには安心して使え ない ◦ Mutableなオブジェクトは、安全にキャッシュできない(キーが変更されうる) ◦ Mutableなオブジェクトは、マルチスレッド環境では安心して使えない(ス レッド間で正しく同期させる必要がある) ◦ 色々理由はあるけど、今後のことを考えてMutableなオブジェクトはなるべ く使わない方向にしたよ、ということ。 15
  • 16. First-Class and Higher Order-Functions(1) • 関数型プログラミングの特徴(要件) ◦ 関数自身を値として他のデータと同様に取り扱える =関数を引数や戻り値として取り扱える • 例:call_twice # Ruby # Python def call_twice(x, &f) def call_twice(f, x): f.call(x) f(x) f.call(x) f(x) end call_twice(print, 123) call_twice(123) {|x| puts x} 16
  • 17. First-Class and Higher Order-Functions(2) • Clojure では... まあ普通な感じ ;Clojure (defn call-twice [f x] (f x) (f x)) (call-twice println 123) 17
  • 18. First-Class and Higher Order-Functions(3) • map (clojure.core/map) (map clojure.string/lower-case [“Java” “Imperative” “Weeping” “Clojure” “Learning” “Peace”]) ;= (“java” “imperative” “weeping” “clojure” “learning” “peace”) (map * [1 2 3 4] [5 6 7 8]) ;collection が複数ある場合 ;= (5 12 21 32) ;中身としては (map #(* % %2) [1 2 3 4] [5 6 7 8]) (map * [1 2 3] [4 5 6 7] [8 9 10 11 12]) ;= (32 90 180) ;※要素の数は少ない方に合わせられる ;中身としては (map #(* % %2 %3) [1 2 3] [4 5 6 7] [8 9 10 11 12]) 18
  • 19. First-Class and Higher Order-Functions(4) • reduce (clojure.core/reduce) (reduce max [0 -3 10 48]) (max 0 -3) ;= 0 (max 0 10) ;= 10 (max 10 48) ;= 48 ;= 48 (のはず P.63 には 10と書いてある...) (max (max (max 0 -3) 10) 48) ;= 48 ;あるいは以下のようも書ける (reduce #(max % %2) [0 -3 10 48]) 19
  • 20. First-Class and Higher Order-Functions(5) • (reduce reduce (clojure.core/reduce) 続き (fn [m v] ; (fn []... ) anonymous function (assoc m v (* v v))) {} [1 2 3 4]) ;(assoc {} 1 (* 1 1)) => {1 1} ;(assoc {1 1} 2 (* 2 2)) => {2 4,1 1} ;(assoc {2 4,1 1} 3 (* 3 3)) => {3 9,1 1,2 4} ;(assoc {3 9,1 1,2 4} 4 (* 4 4)) => {4 16,1 1,2 4,3 9} ;= {4 16, 3 9, 2 4, 1 1} ;あるいは以下のようも書ける (reduce #(assoc % %2 (* %2 %2))) ; #(...) function literal {} [1 2 3 4]) 20
  • 21. First-Class and Higher Order-Functions(6) • Applying Ourselves Partially (関数部分適用の話) (def only-strings (partial filter string?)) ;= #’user/only-strings (only-strings [“a” 5 “b” 6]) ;= (“a” “b”) ;ところで only-strings の正体って何? only-strings ;= #<core$partial$fn__3794 clojure.core$partial$fn__3794@5719510f> ;関数っぽい (class only-strings) ;= user$only_strings ;だそうで... 21
  • 22. First-Class and Higher Order-Functions(7) • Applying Ourselves Partially (関数部分適用の話) partial versus function literals. ; only-strings 相当のことを関数リテラルでやってみる (#(filter string? %) [“a” 5 “b” 6]) ;= (“a” “b”) ; できた!簡単! ;filter の述語を置き換える、なんてことも... (#(filter % [“a” 5 “b” 6]) string?) ;= (“a” “b”) (#(filter % [“a” 5 “b” 6]) number?) ;= (5 6) ;partial じゃなく関数リテラルだけでもいいんじゃ?.... ; => partial の場合、引数を厳密に指定しなくてもよい場合 にすっきり見える (次ページ) 22
  • 23. First-Class and Higher Order-Functions(8) • Applying Ourselves Partially (関数部分適用の話) partial versus function literals. (続き) ;まずは関数リテラル (#(map *) [1 2 3] [4 5 6] [7 8 9]) ;= ArityException Wrong number of args (3) passed ... (#(map * % %2 %3) [1 2 3] [4 5 6] [7 8 9]) ;= (28 80 162) (#(map * % %2 %3) [1 2 3] [4 5 6]) ;= ArityException Wrong number of args (2) passed ... (#(apply map * %&) [1 2 3] [4 5 6] [7 8 9]) ;= (28 80 162) (#(apply map * %&) [1 2 3]) ;= (1 2 3) ; %& で引数の数は気にしなくて良くなったが apply がうっとおしい... ;次に partial の出番 ((partial map *) [1 2 3] [4 5 6] [7 8 9]) ;= (28 80 162) ((partial map *) [1 2 3]) ;= (1 2 3) 23
  • 24. Composition of Function(ality)(1) • Composition って何? (defn negated-sum-str [& numbers] 10 12 3.4 (str (- (apply + numbers)))) ;= #’user/negated-num-str (negated-sum-str 10 12 3.4) + ;= “-25.4” 25.4 (def negated-sum-str (comp str - +)) - ;= #’user/negated-num-str ;※関数を返してくれる! -25.4 ;しかもpartial同様引数の個数とか気にしない! str (negated-sum-str 10 12 3.4) ;= “-25.4” “-25.4” ※P71.脚注26 “point-free style” (引数を明示的に指定・参照しないスタイル) 24
  • 25. Composition of Function(ality)(2) • Composition もう一つの例(camel->keyword) (require '[clojure.string :as str]) (def camel->keyword (comp keyword str/join (partial interpose -) (partial map str/lower-case) #(str/split % #"(?<=[a-z])(?=[A-Z])"))) ;= #'user/camel->keyword (camel->keyword "CamelCase") ;= :camel-case (camel->keyword "lowerCamelCase") ;= :lower-camel-case ;; 上記場面では、以下のように ->> を使うこともできる(こっちのほうが多いかな?) ;; ※comp とは順番が異なることに注意。またcompで必要だった partial 等も不要。 (defn camel->keyword [s] (->> (str/split % #"(?<=[a-z])(?=[A-Z])") (map str/lower-case) (interpose -) str/join keyword)) 25
  • 26. Composition of Function(ality)(3) • camel->keywordを応用してみる(camel-pairs->map) (def camel-pairs->map (comp (partial apply hash-map) (partial map-indexed (fn [i x] (if (odd? i) x (camel->keyword x)))))) ;= #'user/camel-pairs->map (camel-pairs->map ["CamelCase" 5 "lowerCamelCase" 3]) ;= {:camel-case 5, :lower-camel-case 3} 26
  • 27. Composition of Function(ality)(4) • Writing Higher-Order Functions ;お約束の adder (defn adder ; 「関数」を戻り値として返す [n] (fn [x] (+ n x))) ;= #'user/adder ((adder 5) 18) ;= 23 (defn doubler ; 関数をパラメータとして渡す [f] (fn [& args] (* 2 (apply f args)))) ;= #'user/doubler (def double-+ (doubler +)) ;= #'user/doubler-+ (double-+ 1 2 3) ; Clojureの+はいくつでも引数を取れる。便利。 ;= 12 27
  • 28. Composition of Function(ality)(5) • Building a Primitive Logging System with Composable Higher-Order Functions • 高階関数を使ってログ出力をいろいろ作ってみる。 print-logger パラメータwriterを出力先に指定できる関数を返す。 *out-logger* print-logger をつかった、*out* に出力する関数。 retained-logger print-logger をつかった、StringWriter に出力する関数。 file-logger パラメータfileを出力先に指定できる関数を返す。 log->file “message.log”というファイルに出力する関数。 multi-logger logger関数を複数順番に呼び出す(doseq)関数を返す。 log multi-loggerを使って、*out*と”message.log”に出力する関数。 timestamped-logger ログメッセージに日時を付加する関数を返す。 log-timestamped 今までの集大成。 コードは長いのでスライド上は省略します。gist に貼ってありますので、そちらをご参照願います。 https://gist.github.com/3173902/ 28
  • 29. Pure Functions • Pure Functionって何? • 「副作用」(side effects)のない関数、のこと • じゃあ「副作用のある関数」って何? 1. ランダムな状態に依存(乱数を使ってる、とか) 2. 1回めの呼び出しと次回以降の呼び出しで結果が変わる ※I/Oを実行する関数は副作用あり。 (P.77 では @ClojureBook のフォロワー数の出力を例示 →呼び出したタイミングにより値が変わる) 29
  • 30. Pure Functions • Why Are Pure Functions Interesting? • Pure functions are easier to reason about. • 入力パラメータが決まれば出力は必ず同じ出力になる。 • Pure functions are easier to test. • (関数を実行する時点の)状態を考える必要がないのでテストしやすい。 • Pure functions are cacheable and trivial to parallelize. • 入力パラメータが決まれば出力は必ず同じー>入力パラメータに対応し た出力結果をキャッシュ(メモ化)することで、2回目以降の呼び出しを 高速化できる。 (次ページにメモ化の例) 30
  • 31. Pure Functions • メモ化の例(素数判定) (defn prime? [n] (cond (== 1 n) false (== 2 n) true (even? n) false :else (->> (range 3 (inc (Math/sqrt n)) 2) (filter #(zero? (rem n %))) empty?))) (time (prime? 1125899906842679)) ; "Elapsed time: 2181.014 msecs" ;= true (let [m-prime? (memoize prime?)] ; memoize:「関数をメモ化した関数」を返す。 (time (m-prime? 1125899906842679)) (time (m-prime? 1125899906842679))) ; "Elapsed time: 2085.029 msecs" ; "Elapsed time: 0.042 msecs" 31
  • 32. Functional Programming in the Real World Functional Programming in the Real World メリット •予測しやすいコード •テストの容易さ •再利用の容易さ 32

Notes de l'éditeur

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n