Unison で Hello World と FizzBuzz


概要

Unison という開発中のプログラミング言語を触ってみました。
おそらく日本で最初の Unison の記事です。
"3-clause BSD" LICENSE のもとに配布されています。

言語の特徴

  • 静的型付き純粋関数型
  • モダンで Haskell に似た文法を持つ
  • 分散システムでも1つのプログラムで動かせる

環境構築

Unison の開発環境を構築します。

  1. Haskell Stack のインストール
  2. リポジトリの取得
    git clone --recursive https://github.com/unisonweb/unison.git
  3. ビルド&テスト
    stack build && stack exec tests
  4. 初期設定
    stack exec unison init
  5. 起動1
    stack exec unison
  6. ".base" ライブラリの取得
    起動したインタラクティブシェルで以下のコマンドを実行します。
.> pull https://github.com/unisonweb/base .base

エラーが出なければ環境構築は終了です。

Hello World

unison を起動したディレクトリに scratch.u というファイルを作成します。
デフォルトではこのファイルが自動的に watch されます。
scratch.u をテキストエディタで開いて以下のコードを入力します。

scratch.u
hello : '{IO} ()
hello = '(base.io.printLine "Hello world!")

ファイルを保存すると repl が実行されます。

.> 

  I found and typechecked these definitions in
  ~/projects/unison/scratch.u. If you do an `add` or `update`,
  here's how your codebase would change:

    ⍟ These new definitions are ok to `add`:

      hello : '{IO} ()

  Now evaluating any watch expressions (lines starting with
  `>`)... Ctrl+C cancels.

インタラクティブシェルでコマンドを実行してみましょう。

.> run hello
Hello world!
.> 

おめでとうございます。これであなたも unison を完全に理解できましたね!

Namespace

利便性のために namespace を分けてみましょう。
新しい namespace を作成して、そこに hello 関数を移動します。

.> で始まる行は unison インタラクティブシェルで実行します。
注意: .>.mylibrary>入力しません。

  1. namespace の作成
    .> namespace mylibrary
  2. namespace の移動
    .> cd .mylibrary
    .mylibrary>
  3. 関数の移動
    .mylibrary> move.term .hello hello
  4. namespace の探索
    .mylibrary> find

1. hello : '{IO} () が表示されれば "mylibrary" namespace に hello を移動できたことになります。

Publish

コードを GitHub repository に namespace を publish してみましょう。

  1. Github Repository の作成
    Github に repository を作成します。 仮に "myunisonrepo" という名前とします。
  2. namespace の移動
    .mylibrary> cd .
  3. release namespace の複製
    .> copy.namespace mylibrary mylibrary.releases.v1
  4. 動作確認
    .> cd mylibrary.releases.v1
    .mylibrary.releases.v1> find
  5. publish
    cd .mylibrary
    push [email protected]:<yourgithubuser>/myunisonrepo

エラーが出なければ成功です。
push に失敗した場合には github の認証を確認してください。

下記のような構成が repository に作られます。

FizzBuzz

Unison で FizzBuzz を書いてみましょう。

scratch.u
use .base

fizzBuzz : Nat -> Text
fizzBuzz n =
  case (mod n 3, mod n 5) of
    (x,y) | (x == 0) && (y == 0) -> "FizzBuzz"
    (x,_) | (x == 0) -> "Fizz"
    (_,y) | (y == 0) -> "Buzz"
    _ -> toText n

> map fizzBuzz (range 1 101)

Nat は自然数、Text は文字列の型です。
fizzBuzz : Nat -> Text は自然数を引数に取り文字列を返す関数 fizzBuzz を表しています。
range 1 101 は1から100までの自然数の List です。
map 関数に fizzBuzz をつけて自然数の List に適用すると以下の出力が得られます。

           [ "1",
             "2",
             "Fizz",
             "4",
             "Buzz",
             "Fizz",
             "7",
             "8",
             "Fizz",
             "Buzz",
             "11",
             "Fizz",
             "13",
             "14",
             "FizzBuzz",
             "16",
             "17",
             "Fizz",
             "19",
             "Buzz",
             ...(以下略)

気になったこと

  • Haskell が書ける人には書きやすい。
  • ファイルモジュールではなくて namespace 単位で分別するなどの独特の思想が面白い。
  • publish した repository 内のバイナリファイルに可読性がないのでドキュメントが必須。

注意

  • Unison は開発中の言語なので仕様が大きく変わる可能性があります。執筆時点の最新バージョンを使いました。
  • 情報が少なく仕様歴も浅いので仕様を完全には把握していません。間違っている記述を発見したらご指摘いただけると助かります。

  1. 起動まで成功するとインタラクティブシェルが立ち上がります。