VSCodeでClojureのfizzbuzzを書く
さて、REPLを使って関数を即時に実行できるようになったので、次はfizzbuzzで繰り返しと条件分岐を書いてみる。
ここでfizzbuzzとは以下の仕様を満たす関数のこととする。
1から100までの数字を順番に処理する。
数字が3で割れる時、fizzと標準出力に表示する。
数字が5で割れる時、buzzと標準出力に表示する。
数字が3でも5でも割れる時、fizzbuzzと標準出力に表示する。
関数を定義する
まずfizzbuzz関数自体を定義する。
code:main.clj
(defn fizzbuzz [])
そして実行する。
code:main.clj
(fizzbuzz)
;; => nil
nilが返ってくる。理由は簡単で、何もしてないからだ。
上のfizzbuzzを日本語に直すと以下のようになる。
「fizzbuzzという名前の関数を定義します(defn)。
引数はありません([])。
処理内容もありません([]の後ろに何も書いていない)。」
print fizzbuzz!
とりあえずなにかさせよう。必ずfizzbuzzを返すようにしよう。
code:main.clj
(defn fizzbuzz []
(println "fizzbuzz"))
実行する。
code:main.clj
(fizzbuzz)
;; fizzbuzz
;; => nil
標準出力にfizzbuzzが表示された。
ループ
実際にコードを書く時はあんまり使わないのだが、Clojureにもfor関数がある。
名前が他の言語の経験者に馴染みやすいし、Clojureでよくある関数の構文の例として悪くないので、forを使って1から100までの数字を順番に処理してみる。
code:main.clj
(defn fizzbuzz []
(println i))
;; 1
;; 2
;; 3
;; ...(省略)
;; => (nil nil nil ...(省略))
forは第一引数にシーケンスを取り、その中で宣言された変数を使って第2引数以降の関数を実行してくれる。
ここではiという名前で(range 1 101)の結果を1つずつ取得し、シーケンスが終わるまでその内容を標準出力に表示する。
条件分岐
最後に条件分岐を実装する。
条件分岐にはもちろんif関数を使う。
code:main.clj
(defn fizzbuzz []
(if (= (rem i 3) 0)
(if (= (rem i 5) 0)
(println "fizzbuzz")
(println "fizz"))
(if (= (rem i 5) 0)
(println "buzz")))))
実行するといい感じにfizzbuzzが出てくる。
追試: キレイな条件分岐
上のコードは仕様に忠実な書き方だがさすがに冗長だ。3でも5でも割れるのはすなわち15で割れることなので、それを踏まえて違う関数を使ってもう少しキレイに書き直す。
code:main.clj
(defn fizzbuzz []
(cond
(= (rem i 3) 0) (println "fizz")
(= (rem i 5) 0) (println "buzz")
(= (rem i 15) 0) (println "fizzbuzz"))))