LoginSignup
3
2

More than 5 years have passed since last update.

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

Posted at

Shenについて

Shenは、下記の特徴を持ったLisp系の言語です。
特にパターンマッチングや静的片付けに関する部分が気になりました。

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

インストール

Downloadからソースをダウンロードできます。
実行環境はいくつもありますので、お好みのものをお選びください。
今回は手元にあったRuby版を採用。下記環境で試しています。

  • Windows 7
  • Ruby 1.9.3

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

実行

実行はsrreplでOK。
以降は、Shen in 15 minutesの内容を、順不同にかいつまんで書いていきます。

>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は面白いかなと思います。引き続きウォッチはしていこうかな。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2