[Coding Kata]schemeでアナグラムを書いてみた

# 概要

Clean Coder を立ち読みして、コード型の考え方が自分に合ってそうだったのでやってみる。
カタは空手の型から来ているらしい。
基礎練とかそういうの好きなので、こういう地味な基礎練的なのは自分に合っている。と思う。

## 今回のお題

お題は[CodingDojo](http://codingdojo.org/kata/)というサイトから取ってくる。
今回は[Anagram](http://codingdojo.org/kata/Anagram/)をやってみる。

### 課題
標準入力で単語を受け取って、アナグラムを二つ作って返す。

- 例) `scheme -> chesem, hcemse`

### 使用言語

今回はなんとなく好きなschemeでやってみる。
(シンプルに書けて考え方がわかりやすいと思ったので)

- 今回使用した環境
  - gauche 0.9.5

ちなみにgaucheはscheme処理系の一つ。
他の処理系(racketとか)より機能が充実してて便利なので、schemeやるならオススメ。らしい。

### 解いてみる

schemeで受け取った文字列を変換し、アナグラムを作って出力させる関数を作る。

schemeでこれをプログラミングする時、次の2つを考える必要がある。
1. 受け取った文字列をリスト化する
2. ランダムにアナグラム化するロジックを考える必要がある。

1. でリスト化することはそれほど難しくない。
schemeの文字列はダブルクォートで囲むことで作成できる。

```
gosh> (define s "scheme")
gosh> (string? s)
#t                             
```

文字列から一文字づつ取り出してconsしてリスト化しようと思ったけど、
string->listで文字列をリスト化できるのでこっちを使う。

```
gosh> (define slist (string->list s))
slist
gosh> slist
(#\s #\c #\h #\e #\m #\e)
gosh> (pair? slist)
#t
```

2.の方がいまいち思いつかない。
乱数を使って文字列から一文字づつ取り出し、consするとかだろうか…
と思ったらすでに関数があった。

https://practical-scheme.net/gauche/man/gauche-refj/sikensuhuremuwaku.html

ここのshuffleという関数を使う。

これを使うためにuseマクロでgauche.sequenceを取り込む

```
gosh> (use gauche.sequence)
```

これはrequireしてimportするのと同じ

```
gosh> (require "gauche/sequence")
gosh> (import gauche.sequence)
```

requireすることで、別ファイルの関数を読み込み、評価し、importすることで変数や関数を取り込んで使える様にしている。

```
gosh> (shuffle slist)
(#\c #\h #\e #\e #\s #\m)
gosh> (shuffle slist)
(#\m #\s #\e #\c #\e #\h)
```

最後にlistをstringに戻す。listをstringに戻すにはlist->stringを使う

```
gosh> slist
(#\s #\c #\h #\e #\m #\e)
gosh> (list->string slist)
"scheme"
```

shuffleした結果をlist->stringで元に戻すにはこう書く。

```
gosh> (list->string (shuffle slist))
"echmes"
gosh> (list->string (shuffle slist))
"cemehs"
```

これでできそう。コードを書いてみる。

```
;; 受け取った文字列をランダムでアナグラム化する
;; shuffle用にmoduleをインポートする
(use gauche.sequence)

(define (anagram str)
  (let ((slist (string->list str)))
    (let ((agm1 (list->string (shuffle slist)))
          (agm2 (list->string (shuffle slist))))
      (list agm1 agm2))))
```

実行結果は下記の通り

```
gosh> (anagram "scheme")
("meshec" "ceehsm")
```

ここでは、返却値をアナグラムした結果のリストにした。(テスト可能なコードにするため)

# テストする

さらに、テストコードを書いていく。テストの合格条件は以下2つ。

1. 返却したリストの要素数が2つであること
2. リストの文字列が引数のアナグラムであること

1.は簡単。リストの要素数をlengthで調べれば良い。

```
gosh> (length (anagram "scheme"))
2
```

2.の方が重要。ここでは、引数とアナグラムの結果両方をソートして比較する。
sortを使えば、文字列もソートしてくれる。

```
gosh> s
"scheme"
gosh> (sort s)
"ceehms"
```

アナグラムの結果もsortする。結果は同じになる。

```
gosh> (define anagram-list (anagram "scheme"))
anagram-list
gosh> anagram-list
("escmeh" "cmsehe")
gosh> (sort (car anagram-list)) ;; "escmeh"をソート
"ceehms"
gosh> (sort (cadr anagram-list)) ;; "cmsehe"をソート
"ceehms"
```

これらを使ってテストコードを書く。テストには[gauche.test](https://practical-scheme.net/gauche/man/gauche-refj/Dan-Ti-tesuto.html)を使う。

testディレクトリを作成して、その中にテストコードを放り込む。ディレクトリ構成はこんな感じ

```
.
├── anagram.scm
└── test
    └── anagram-test.scm
```

テストコードはこう書く。

```
(use gauche.test)
(test-start "anagram")
(load "../anagram.scm")

;; テスト用にアナグラム結果のリストを作る。
(define str "scheme")
(define test-anagram-list (anagram str))

(test-section "anagram-test")

;; アナグラム結果が2つであることをテスト
(test* "number of anagram list" 2 (length test-anagram-list))

;; アナグラムが正しくできていることのテスト
;; 比較用に引数をsortした文字列を用意
(define sorted-str (sort str))

(test* "anagram 1" sorted-str (sort (car test-anagram-list))) ;; 一つ目のテスト
(test* "anagram 2" sorted-str (sort (cadr test-anagram-list))) ;; 二つ目のテスト

(test-end)
```

テスト結果

```
gosh> Testing anagram ...
#<undef>
gosh> #t
gosh> str
gosh> test-anagram-list
gosh> <anagram-test>-----------------------------------------------------------------
#<undef>
gosh> test number of anagram list, expects 2 ==> ok
#<undef>
gosh> sorted-str
gosh> test anagram 1, expects "ceehms" ==> ok
#<undef>
gosh> test anagram 2, expects "ceehms" ==> ok
#<undef>
gosh> passed.
0
```

# 所感

あんまり大したことやってないけどどうせなのでまとめてみた。
今回はライブラリに頼りすぎてて自分で考えてない感が強いので、次はもっとゴリゴリ書いてみたい。

# 参考

- [Coding Dojo kata](http://codingdojo.org/kata/)
  - いろんなお題があって見てるだけで楽しい。
- [Gauche ドキュメント](https://practical-scheme.net/gauche/man/gauche-refj/puroguramunorodo.html)
  - Gaucheのことで困ってたらここを見れば大体載ってた。助かった。