Common Lisp で Fizz Buzz

# 概要

- テーマ: Common Lisp
- 目的: Fizz Buzz を書く
- 前提: 私は素人です
- いろんな言語でFizzBuzzを書こうという社内勉強会で使った資料です

----

# 環境構築(macOS)

こちら実行しておいてください

```shell
brew install roswell
ros setup
ros run
```

[roswell](https://github.com/roswell/roswell): Common Lisp の rbenv みたいなやつ

----

# LISP とは

- 1958年に生まれたプログラミング言語
    - FORTRAN(1954年生まれ)より4年新しい
    - COBOL(1959年生まれ)より1年古い
    - C言語(1972年生まれ)より14年古い
- **LIS**t **P**rocessor (リスト処理機)
- 現在方言である[Common Lisp](https://ja.wikipedia.org/wiki/Common_Lisp), [Scheme](https://ja.wikipedia.org/wiki/Scheme), [Clojure](https://ja.wikipedia.org/wiki/Clojure), [Emacs Lisp](https://ja.wikipedia.org/wiki/Emacs_Lisp) などが主に使われてる。(リンクはWikipediaの記事へのリンク)

----

# コードの見た目

<a href="https://gyazo.com/37a08fa05c46755d7625f38a3e3f078b"><img src="https://i.gyazo.com/37a08fa05c46755d7625f38a3e3f078b.png" alt="Image from Gyazo" width="325" /></a>

[https://github.com/google/lisp-koans/blob/master/koans/iteration.lsp より](https://github.com/google/lisp-koans/blob/master/koans/iteration.lsp)

----

# コードの見た目

- `()` だらけ！
- LISPではデータも処理も全てがリストで表現される
- このリストを[S式](https://ja.wikipedia.org/wiki/S%E5%BC%8F)と呼ぶ
    - `'(1 2 3 4 5)` 1から5までのリスト -> S式
    - `(+ 1 2 3 4 5)` 1から5までを加算する処理 -> S式


----

# まずは足し算から

```lisp
(+ 1 2)
```

- `(+ 1 2)`: LISPでは `(関数名 引数1 引数2 ...)` で関数を実行する
    - `+`: 足し算を行う関数
    - `1`: 引数1
    - `2`: 引数2

----

# hello, world!

```lisp
(format t "hello, world")
```

- `format` 関数に
    - 引数1: `t` (真値)(標準出力をあらわす)
    - 引数2: `"hello, world"` 出力する文字列

----

# 条件分岐

```lisp
(if
 (= 1 1)
 (format t "then")
 (format t "else"))
```

- `if` 関数に3つの引数を与えて評価する
    - 引数1: `(= 1 1)`
        - 条件式
        - 比較を行う関数 `=` に `1` と `1` を与えて評価している
    - 引数2:`(format t "then")`
        - 条件がnilでない時に評価される式
    - 引数3:`(format t "else")`
        - 条件がnilの時に評価される式

----

# 繰り返し

```lisp
(dotimes
  (i 100)
  (format t "~a " i))
```

- `dotimes` マクロ
    - 引数1: `(カウンター リミット dotimesの評価値)`
        - マクロなので `(i 100)` が関数として評価されてないことに注目
    - 引数2: 実行する式
- マクロは制御構文を自分で作るためのLISPの機能
    - (勉強不足です)

----

# 変数

```lisp
(let
  (value1 value2)
  (setq value1 "My Name is")
  (setq value2 "牛乳")
  (format t "~a ~a" value1 value2))
;--> "My Name is 牛乳"
```

- `let`: 局所変数とスコープを定義する特殊式
    - `(value1 value2)`: (let)内で使用する局所変数のリスト
    - `(setq ...) (...)`: 以下の式では局所変数のスコープ内になる
    - (特殊式って？)(勉強不足です)

----

# Fizz Buzz

```lisp
(dotimes (i 100)                     ; マクロ. (dotimes (カウンタ変数 繰り返し数 dotimesの返り値) E0 E1 ...)
  (let (num)                         ; (let (V0 V1 V2 ...) E0 E1 E2 ...) 局所変数を定義する
    (setq num (+ i 1))               ; num に i + 1 を代入
    (if (= 0 (mod num 3))            ; Fizzを判断
      (format t "Fizz")              ; Fizzを出力
      nil)                           ; else節(なにもしない)
    (if (= 0 (mod num 5))            ; Buzzを判断
      (format t "Buzz")              ; Buzzを出力
      nil)                           ; else節(なにもしない)
    (if (and (not (= 0 (mod num 5))) ; FizzでもBuzzでもないのを判断
             (not (= 0 (mod num 3))));
      (format t "~a" num))           ; 数字を出力
    (format t " " )))                ; すきま

; 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz
```

----

# Fizz Buzz 2

```lisp
; counter 個のインクリメンタルなリストを作る
(defun iota (counter &optional (start 0))
  (if (= counter 0)
    nil
    (cons start (iota (- counter 1)
                      (+ start 1)))))
; FizzBuzz を返す
(defun fizz_buzz (num)
  (cond ((and (= 0 (mod num 3)) (= 0 (mod num 5))) "FizzBuzz")
        ((= 0 (mod num 3)) "Fizz")
        ((= 0 (mod num 5)) "Buzz")
        (t num)))
; 出力
(format t
        "~{~a ~}"
        (mapcar #'fizz_buzz (iota 100 1)))

```

----

# 参考記事

- [いまから始めるCommon Lisp - Qiita](https://qiita.com/t-sin/items/054c2ff315ec3b9d3bdc)
- [誰向けかわからないCommon Lispでの関数型プログラミング入門とその未来 - 八発白中](http://blog.8arrow.org/entry/2014/02/04/041417)
- [Lisp 一夜漬け](http://www.haun.org/kent/lisp1/)
- [Common Lisp 入門 - M.Hiroi's Home Page](http://www.nct9.ne.jp/m_hiroi/xyzzy_lisp.html#abclisp)
- [独学 Common Lisp](https://lisp.satoshiweb.net/)
- [逆引きCommon Lisp](https://lisphub.jp/common-lisp/cookbook/index.cgi)
- [Lispプログラミング入門 - 田村 直之 : 神戸大学 情報基盤センター](http://bach.istc.kobe-u.ac.jp/lect/ProLang/org/lisp.html)
- [On Lisp](http://www.asahi-net.or.jp/~kc7k-nd/onlispjhtml/index.html)
- [Common Lispの勉強をするには、あるいは情報を得るには - κeenのHappy Hacκing Blog](https://keens.github.io/blog/2014/10/20/lisp-ja/)