ShenのチュートリアルをやってFizzBuzzを書くまで試した

# Shenについて
[Shen](http://shenlanguage.org/)は、下記の特徴を持ったLisp系の言語です。
特にパターンマッチングや静的片付けに関する部分が気になりました。

* パターンマッチング
* 一貫性のあるラムダ計算
* マクロ
* 遅延評価(がオプションである？部分的に？ちょっとわかりませんでした)
* 静的型付け
* functional Prologとの統合(?)
* コンパイラコンパイラ

# インストール
[Download](http://www.shenlanguage.org/Download/download.html)からソースをダウンロードできます。
実行環境はいくつもありますので、お好みのものをお選びください。
今回は手元にあったRuby版を採用。下記環境で試しています。

* Windows 7
* Ruby 1.9.3

`gem install shen-ruby` で簡単にインストールできます。

# 実行
実行は`srrepl`でOK。
以降は、[Shen in 15 minutes](http://www.shenlanguage.org/learn-shen/tutorials/shen_in_15mins.html#shen-in-15mins)の内容を、順不同にかいつまんで書いていきます。

```
>srrepl
Loading.... Completed in 7.48 seconds.

Shen 2010, copyright (C) 2010 Mark Tarver
released under the Shen license
www.shenlanguage.org, version 14
running under Ruby, implementation: ruby 1.9.3
port 0.8.0 ported by Greg Spurrier


(0-)
```

最後の(0-)というのは、0番目の式の入力プロンプト、`-`記号は型チェックしていない状態を意味します。

型チェックを有効にするには`(tc +)`と実行すればOK。
※以降、入力プロンプト内の番号は省略します

```
(-) "abc"
"abc"

(-) (tc +)
true

(+) "abc"
"abc" : string
```

型を語って来ました。折角なので、type checkingを有効にしたまま次に進みます。
リストは`[ ]`で表します。リストの中には、type checking有効時には、型の互換性があるものしか入れられない模様です。
```
(+) a
a : symbol

(+) 1
1 : number

(+) [a b c]
[a b c] : (list symbol)

(+) [a 1]
type error
```

式の実行はいつものLispです。

```
(+) (+ 1 2 3 4 5)
15 : number

(+) (and true false)
false : boolean
```

試しに`and`の第2引数にnumberを入れてみたところ、当然怒られましたので、andの型を見てみます。
なんと、`and`は、2つのbooleanを受け取り1つのbooleanを返す関数だったのです(そりゃそうだ)。
それよりも、Haskellのような記法で型の情報が出力されていることが気になります。
これはまさか…と、`(and true)`と実行した結果、1つのbooleanを受け取り1つのbooleanを返す関数が返ってきました。
何とカリー化も用意されている模様。

```
(+) (and true 3)
type error

(+) and
and : (boolean --> (boolean --> boolean))

(+) (and true)
#<Proc:0x3b2a6e8 (lambda)> : (boolean --> boolean)
```

自分でも式を定義してみます。試しに、2乗を返す関数を定義してみます。
関数名、型、処理内容の順番で書くようです。また、type checkingを無効にしている場合、型の記載は不要とのこと。

```
(+) (define square
{number --> number}
X -> (* X X))
square : (number --> number)

(+) (square 4)
16 : number
```

何となく雰囲気がわかってきたので、そろそろFizzBuzzを書いてみようかと。

# FizzBuzzを書いてみる
FizzBuzzを関数型ちっくに解くには、以下が必要です。

* number --> string のfizzbuzz関数
* 1, 2, 3, ... となる数値リストの生成
* mapで数値リストをFizzBuzzの文字列リストに変換

## number --> string のfizzbuzz関数
※業務連絡 ここからまた`(tc -)`します。何故か余りの計算方法が`(tc +)`のときにわかりませんでした…

fizzbuzz関数は下記のように定義します。パターンマッチングを用い、15で割り切れる場合、3で割り切れる場合、5で割り切れる場合、それ以外の4パターン用意します。余りの計算は`shen.mod`関数を使う模様。
手動テストの結果、うまく動いている模様です。

```
(16-) (define fizzbuzz
X -> "FizzBuzz" where (= 0 (shen.mod X 15))
X -> "Fizz" where (= 0 (shen.mod X 3))
X -> "Buzz" where (= 0 (shen.mod X 5))
X -> (str X))
fizzbuzz

(17-) (fizzbuzz 1)
"1"

(18-) (fizzbuzz 2)
"2"

(19-) (fizzbuzz 3)
"Fizz"

(20-) (fizzbuzz 4)
"4"

(21-) (fizzbuzz 5)
"Buzz"

(22-) (fizzbuzz 6)
"Fizz"

(23-) (fizzbuzz 15)
"FizzBuzz"

(24-) (fizzbuzz 16)
"16"
```

## 1, 2, 3, ... となる数値リストの生成
探してみたのですが、標準での取得方法がわかりませんでした。ですので、とりあえず100まで生成する関数を自作します。

```
(56-) (define number-list
X Y -> [] where (> X Y)
X Y -> [X | (number-list (+ 1 X) Y)]
)
number-list

(57-) (number-list 1 10)
[1 2 3 4 5 6 7 8 9 10]
```

## mapで変換
mapは標準関数としてありました。これで、数値のリストをfizzbuzz関数で変換することができます。

```
(60-) (map fizzbuzz (number-list 1 20))
["1" "2" "Fizz" "4" "Buzz" "Fizz" "7" "8" "Fizz" "Buzz" "11" "Fizz" "13" "14" "FizzBuzz" "16" "17" "Fizz" "19" "Buzz"]
```

何とかFizzBuzzができた…

## ハマった点
type checking有効時に余りの計算が出来なかった件。実行環境のバグだとは思いますが、ハマりました…

```
(67+) (tc -)
false : boolean

(68-) shen.mod
shen.mod

(70-) (shen.mod 5 3)
2

(71-) (tc +)
true

(72+) shen.mod
shen.mod : symbol

(73+) (shen.mod 5 3)
type error
```

# 感想
Shenのパターンマッチングを使った関数の書き方や静的型付けは、私が知っているSchemeやClojureとは違った書き方ができるので面白いと思います。
しかし一方で、今時点でShenにガッツリハマろうとは思いませんでした。理由は実行環境が複数あり、どれが本命の実行環境か分からないことです。想像ですが、複数の実行環境があると、それだけ開発者が分散してしまうのではないかと思います。結果的に各実行環境の開発者が少なくなり、品質にばらつきが出てしまうのではないかと予想するためです。

とは言え、純粋に仕様だけ見ていれば、Shenは面白いかなと思います。引き続きウォッチはしていこうかな。