読者です 読者をやめる 読者になる 読者になる

Land of Lispを読んでいる。

他にも色々やらなきゃいけないことがあるはずなのに。 とてもおもしろいです。悟りまではまだまだ長い。。

関数型パラダイムが云々みたいな議論に参加する気合はないですが、少なくとも他の言語、特にRuby,を書くときはなんだか頭がフレッシュな感じになる感覚は少しわかるかも。 オブジェクトに対するメッセージングか関数呼び出しかで向きが逆になるのがね。なんともですが。

本文中コードを書いてもただの写経なので、自分のLispのアウトプット能力を確認してみる。

(defun iota (current limit step)
  (if (> current limit)
      nil
      (cons current (iota (+ current step) limit step))))

(defun fizzbuzz (n)
  (cond ((zerop (mod n 15)) "FizzBuzz")
        ((zerop (mod n 3)) "Fizz")
        ((zerop (mod n 5)) "Buzz")
        (t                  n)))

(defun fizzbuzzing (list)
  (if list
      (progn (princ (fizzbuzz (car list)))
             (fresh-line)
             (fizzbuzzing (cdr list)))
      (fresh-line)))

(fizzbuzzing (iota 1 100 1))

後述のrubyのほうが短くてしゅっとしてるけど、再帰的に書くことを意識しますた。

iota 関数でまず引数limitまでの数列のリストを作ります。数列生成の関数をiotaって言うのはなんでなんでしょう。

fizzbuzz関数は、コアになるロジックで、引数に整数をとり、値の15,3,5のmodで条件分岐します。

fizzbuzzing関数は、数列をひたすら右に向かってfizzbuzzしてく再帰関数です。

トップレベルでiotaで作った数列をfizzbuzzingに流して終了。

もっと関数っぽいっていうか宣言的に書ける方法があるような気がします。自然数列とFizzBuzz数列は全単射なわけで...

def fizzbuzz(n)
  str = ""
  str << "Fizz" if (n % 3).zero? 
  str << "Buzz" if (n % 5).zero? 
  str.empty? ? n : str
end

p (1..100).map {|n| fizzbuzz n }

rubyのほうが楽ちんという説は確かにある。

fizzbuzz = -> n {
 n % 15 == 0 ? "FizzBuzz" : 
 n % 3 == 0 ? "Fizz" : 
 n % 5 == 0 ? "Buzz" : 
 "#{n}" 
}
p (1..100).map &fizzbuzz

こんなのもありとどこかの記事を見ていて知った。 色々かっこいい。

追記。

fizzbuzz = -> (n){ "#{"Fizz" if n % 3 == 0}#{"Buzz" if n % 5 == 0}" }
(1..100).each { |n| p fizzbuzz.(n).empty? ? n : fizzbuzz.(n) }

これが一番かっこいいわ。個人的には。