clojure.specの話(仮)

E170ae2eb0adcf3d136ab0990f0ea671?s=47 OHTA Shogo
July 21, 2016
300

 clojure.specの話(仮)

E170ae2eb0adcf3d136ab0990f0ea671?s=128

OHTA Shogo

July 21, 2016
Tweet

Transcript

  1. DMPKVSFTQFDͷ࿩ Ծ OJTIJTIJOKVDMPKVSF !BUIPT

  2. ࣗݾ঺հ ‣ 5XJUUFS!BUIPT ‣ χϟϯύεגࣜձࣾॴଐ ‣ $MPKVSFίϯτϦϏϡʔλ

  3. ૣ଎Ͱ͕͢

  4. $MPKVSFͷҰ൪ ϜΧͭ͘ͱ͜Ζͬͯʁ

  5. Τϥʔϝοηʔδ ࠾༻ εΫϦϓτΛ࡞Δ೉͠͞ υΩϡϝϯτɾνϡʔτϦΞϧ ੩తܕ͕ͳ͍ $MPKVSFTVSWFZʮ$MPKVSFͷҰ൪ϜΧͭ͘ͱ͜Ζ͸ʁʯ

  6. Τϥʔϝοηʔδ

  7. ‣ $MPKVSFͷΤϥʔͷ෼͔Γʹ͘͞͸Α͘ࢦఠ͞ΕΔ ‣ $MPKVSFͷ૊ࠐΈؔ਺ͷଟ͘͸ΨʔϕδΠϯΨʔϕδ Ξ΢τ ‣ Ҿ਺νΣοΫΛೖΕΔͱɺ+*5ίϯύΠϥͷ࠷దԽΛ ્֐͠ɺύϑΥʔϚϯεʹӨڹ͢ΔͨΊ

  8. Կ͕ωοΫ͔ʁ ‣ ύϑΥʔϚϯε໘͔Βߟ͑Δͱ࣮ߦ࣌ͷνΣοΫ͸ ۃྗආ͚͍ͨ ‣ ͔͠͠ɺ੩తܕ͕ͳ͍Ҏ্ίϯύΠϧ͚࣌ͩͰνΣο Ϋ͖͠Δͷ͸೉͍͠ ‣ ։ൃ͚࣌ͩΦϯʹͰ͖ΔҾ਺νΣοΫͷ࢓૊Έ͕͋ Ε͹͍͍

  9. DMPKVSFTQFD

  10. DMPKVSFTQFD ‣ ࣍ظϦϦʔε$MPKVSFͰͷಋೖ͕ਐΊΒΕ͍ͯΔ৽ػೳ ‣ ੩తܕͰͳ͘ɺड़ޠͷ૊Έ߹ΘͤʹΑͬͯσʔλܕͷ࢓༷ Λهड़͢Δ ‣ Ұ౓࢓༷ εϖοΫ Λॻ͚͹ҰཻͰԿ౓΋͓͍͍͠

     υΩϡϝϯςʔγϣϯ  ܖ໿ϓϩάϥϛϯά  ϓϩύςΟϕʔεςετ  ϚΫϩͷߏจνΣοΫ
  11. DMPKVSFTQFDͷ࢖͍ํ ‣ [org.clojure/clojure “1.9.0-alphaXX”] Λ:dependenciesʹ௥Ճ ‣ ࠷৽൛͸BMQIB ݱࡏ  ‣

    (require ‘[clojure.spec :as s])
  12. DMPKVSFTQFDೖ໳

  13. ड़ޠ ‣ ड़ޠ CPPMΛฦؔ͢਺ ͸ͦͷ··ͰεϖοΫͱͯ͠ ࢖͑Δ user=> (s/valid? integer? 42)

    true user=> (s/valid? integer? “foo”) false
  14. WBMJE FYQMBJO ‣ WBMJE ͸εϖοΫΛຬ͔ͨ͢Ͳ͏͔Λฦ͢ ‣ FYQMBJO͸εϖοΫΛຬͨ͞ͳ͍ՕॴΛࢦఠ͢Δ user=> (s/valid? integer?

    “foo”) false user=> (s/explain integer? “foo”) val: "foo" fails predicate: :clojure.spec/unknown nil user=> (s/explain integer? 42) Success! nil
  15. εϖοΫͷ߹੒ ‣ BOE΍PSΛ࢖ͬͯෳ਺ͷεϖοΫΛ૊Έ߹ΘͤՄೳ user=> (s/valid? (s/and integer? even?) 0) true

    user=> (s/valid? (s/and integer? even?) 1) false user=> (s/valid? (s/or :int integer? :str string?) “foo”) true
  16. εϖοΫʹ໊લΛ͚ͭΔ ‣ EFGͰεϖοΫʹ໊લΛ͚ͭΔ͜ͱ͕Ͱ͖Δ ‣ εϖοΫࣗମΛ࠶ར༻Ͱ͖Δ user=> (s/def ::answer-to-everything (fn [x]

    (= x 42)) :user/answer-to-everything user=> (s/valid? ::answer-to-everything 43) false user=> (s/valid? ::answer-to-everything 42) true
  17. ίϨΫγϣϯͷεϖοΫ ‣ coll-ofmap-ofͰίϨΫγϣϯͷཁૉ͕εϖοΫ Λຬ͍ͨͯ͠Δ͔νΣοΫͰ͖Δ user=> (s/valid? (s/coll-of integer?) [1 2

    3]) true user=> (s/valid? (s/coll-of integer?) [1 :a]) false user=> (s/valid? (s/map-of keyword? integer?) {:a 0, :b 1}) true user=> (s/valid? (s/map-of keyword? integer?) {:a 0, :b “foo”}) false
  18. ίϨΫγϣϯͷεϖοΫ ‣ ΩʔʹΑͬͯ஋ͷܕ͕ҧ͏ϚοϓͷεϖοΫ΋ఆٛՄೳ user=> (s/def ::x integer?) :user/x user=> (s/def

    ::y string?) :user/y user=> (s/explain (s/keys :req-un [::x ::y]) {:x 1, :y 2}) In: [:y] val: 2 fails spec: :user/y at: [:y] predicate: string? nil user=> (s/valid? (s/keys :req-un [::x ::y]) {:x 1, :y “foo”}) true
  19. DMPKVSFTQFDʹΑΔ ܖ໿ϓϩάϥϛϯά

  20. ܖ໿ϓϩάϥϛϯάͱ͸ ‣ ؔ਺ͷݺͼग़͠ʹؔͯ͠ɺࣄલ৚݅ɾࣄޙ৚݅ɾෆ ม৚݅ΛܾΊɺݺͼग़͢ଆͱݺͼग़͞ΕΔଆͷٛ຿ Λ໌֬ʹ͢Δख๏  ݺͼग़͢ଆɿ ؔ਺Λݺͼग़͢લʹࣄલ৚݅ͱෆม৚݅Λຬͨٛ͢຿Λෛ͏  ݺͼग़͞Εͨଆɿ

    ؔ਺͔Β໭ͬͨޙʹࣄޙ৚݅ͱෆม৚݅Λຬͨٛ͢຿Λෛ͏
  21. ؔ਺ʹର͢ΔεϖοΫ ‣ fizzbuzzؔ਺ͷεϖοΫ͸্ͷΑ͏ʹఆٛͰ͖Δ ‣ :args :ret͕ͦΕͧΕࣄલ৚݅ɾࣄޙ৚݅ʹରԠ (s/fdef fizzbuzz :args (s/cat

    :n (s/and integer? #(> % 0))) :ret (s/or :int integer? :key keyword?)) (defn fizzbuzz [n] (cond (= (mod n 15) 0) :fizzbuzz (= (mod n 5) 0) :buzz (= (mod n 3) 0) “fizz” ;;←όά :else n))
  22. JOTUSVNFOU ‣ ؔ਺ʹҾ਺͕εϖοΫΛຬ͍ͨͯ͠Δ͔ͷνΣοΫ ΛΦϯɾΦϑͰ͖Δ user=> (require ‘[clojure.spec.test :as t]) nil

    user=> (t/instrument) [user/fizzbuzz] user=> (fizzbuzz 15) “fizzbuzz” user=> (fizzbuzz “foo”) ExceptionInfo Call to #'user/fizzbuzz did not conform to spec: In: [0] val: "foo" fails at: [:args :n] predicate: integer? :clojure.spec/args ("foo") … user=>
  23. DIFDL ‣ Ҿ਺ͷεϖοΫΛຬͨ͢஋Λࣗಈੜ੒ͯ͠ɺͦͷ஋Λؔ਺ʹ ౉ͨ݁͠Ռ͕໭Γ஋ͷεϖοΫΛຬ͔ͨ͢νΣοΫ͢Δ user=> (t/check) ({:spec … :clojure.spec.test.check/ret {:result

    #error {:cause "Specification-based check failed” :data {:clojure.spec/problems (… {:path [:ret :key], :pred keyword?, :val “fizz", :via [], :in [], :clojure.spec.test/args (3), :clojure.spec/failure :check-failed}…)} user=>
  24. DIFDL ‣ Ҿ਺ͷεϖοΫΛຬͨ͢஋Λࣗಈੜ੒ͯ͠ɺͦͷ஋Λؔ਺ʹ ౉ͨ݁͠Ռ͕໭Γ஋ͷεϖοΫΛຬ͔ͨ͢νΣοΫ͢Δ user=> (t/check) ({:spec … :clojure.spec.test.check/ret {:result

    #error {:cause "Specification-based check failed” :data {:clojure.spec/problems (… {:path [:ret :key], :pred keyword?, :val “fizz", :via [], :in [], :clojure.spec.test/args (3), :clojure.spec/failure :check-failed}…)} user=> Ͱݺͼग़ͨ͠ͱ͖ʹ ࣦഊ͢Δ͜ͱΛݕग़
  25. DMPKVSFTQFDʹΑΔ ϓϩύςΟϕʔεςετ

  26. ϓϩύςΟϕʔεςετͱ͸ ‣ ී௨ͷςετ FYBNQMFCBTFEUFTUJOH ͷΑ͏ʹɺ ۩ମతͳςετέʔεʹର͢ΔςετͰ͸ͳ͘ɺ೚ ҙͷೖྗʹରͯ͠੒Γཱͭੑ࣭Λهड़ͨ͠ςετ ‣ ೖྗ஋ͷϥϯμϜʹͨ͘͞Μੜ੒͠ɺͦͷ஋ʹର͠ ͯςετΛ࣮ߦ͢Δ

    ‣ )BTLFMMͷ2VJDL$IFDL͕༗໊ ‣ $MPKVSFͰ͸UFTUDIFDLΛ࢖͏ͷ͕ελϯμʔυ
  27. p[[CV[[ؔ਺ͷςετ ‣ εϖοΫΛຬͨ͢஋Λࣗಈੜ੒͠ɺ͢΂ͯͷ஋ʹର ͯ͠ੑ࣭͕੒Γཱ͔ͭͲ͏͔νΣοΫ͢Δ (ns fizzbuzz-test (:require [clojure.test.check.clojure-test :refer [defspec]]

    [clojure.test.check.properties :as prop] [clojure.spec :as s] [fizzbuzz :as fb])) (defspec fizzbuzz-prop (prop/for-all [n (s/gen (s/and integer? #(> % 0)))] (let [v (fb/fizzbuzz n)] (cond (= (mod n 3) 0) (contains? #{:fizz :fizzbuzz} v) (= (mod n 5) 0) (contains? #{:buzz :fizzbuzz} v) :else (= n v)))))
  28. ·ͱΊ ‣ DMPKVSFTQFD͸σʔλܕ΍ؔ਺ͷ࢓༷Λड़ޠͷ૊Έ ߹ΘͤͰهड़͢Δํ๏Λఏڙ͢Δ ‣ Ұ౓εϖοΫΛॻ͘ͱɺίʔσΟϯάத͚ͩͰͳ͘ɺ υΩϡϝϯςʔγϣϯ΍ςετ౳ʹ΋໾ཱͯΒΕΔ ‣ $MPKVSFͷ૊ࠐΈؔ਺ʹର͢ΔεϖοΫ͕༻ҙ͞Ε Ε͹Τϥʔϝοηʔδ΋վળ͞ΕΔ͔΋ʁ

  29. ࠓ೔࿩͞ͳ͔ͬͨ͜ͱ ‣ TDPOGPSN ‣ γʔέϯεʹର͢ΔεϖοΫ ‣ εϖοΫʹΑΔϚΫϩͷߏจղੳ ଓ͖͸ͷ-JTQNFFUVQͰʂʂ