Last active
April 11, 2025 01:25
-
-
Save lagenorhynque/bec8e4a2e856656832605f08dfa8e6d1 to your computer and use it in GitHub Desktop.
『改訂新版 良いコード/悪いコードで学ぶ設計入門』(ミノ駆動本) 3章のサンプルコードを関数型言語Clojureで書いてみる
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns money | |
(:refer-clojure :exclude [+]) | |
(:require | |
[clojure.spec.alpha :as s]) | |
(:import | |
(java.util | |
Currency))) | |
(s/def ::amount nat-int?) | |
(s/def ::currency #(instance? Currency %)) | |
(s/def ::money | |
(s/keys :req-un [::amount | |
::currency])) | |
(defrecord Money | |
[amount | |
currency]) | |
(s/fdef make-money | |
:args (s/cat :amount ::amount | |
:currency ::currency) | |
:ret ::money) | |
(defn make-money | |
[amount currency] | |
(map->Money | |
{:amount amount | |
:currency currency})) | |
(s/fdef + | |
:args (s/and (s/+ ::money) | |
#(apply = (map :currency %))) | |
:ret ::money) | |
(defn + | |
([m] m) | |
([m1 m2] | |
(update m1 | |
:amount | |
clojure.core/+ (:amount m2))) | |
([m1 m2 & more] | |
(reduce + (+ m1 m2) more))) | |
(comment | |
(require '[clojure.repl.deps :refer [add-lib]]) | |
(add-lib 'orchestra) | |
(require '[orchestra.spec.test :as stest]) | |
(stest/instrument) | |
;;; 利用例 | |
(make-money 100 (Currency/getInstance "USD")) | |
;; => {:amount 100, :currency #object[java.util.Currency 0x74f08418 "USD"]} | |
;; 負の数量なので生成できない | |
(make-money -100 (Currency/getInstance "USD")) | |
;; => Execution error - invalid arguments to money/make-money at (test.cljc:30). | |
;; -100 - failed: nat-int? at: [:amount] spec: :money/amount | |
(let [usd (Currency/getInstance "USD") | |
m1 (make-money 100 usd) | |
m2 (make-money 200 usd) | |
m3 (make-money 300 usd)] | |
(+ m1 m2 m3)) | |
;; => {:amount 600, :currency #object[java.util.Currency 0x74f08418 "USD"]} | |
;; 異なる通貨の和は計算できない | |
(let [usd (Currency/getInstance "USD") | |
jpy (Currency/getInstance "JPY") | |
m1 (make-money 100 usd) | |
m2 (make-money 200 usd) | |
m3 (make-money 300 jpy)] | |
(+ m1 m2 m3)) | |
;; => Execution error - invalid arguments to money/+ at (test.cljc:30). | |
;; [#money.Money{:amount 100, :currency #object[java.util.Currency 0x74f08418 "USD"]} #money.Money{:amount 200, :currency #object[java.util.Currency 0x74f08418 "USD"]} #money.Money{:amount 300, :currency #object[java.util.Currency 0x5a87e137 "JPY"]}] - failed: (apply = (map :currency %)) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment