こんにちは、びしょ〜じょです。

さて、Koka言語というものがある。そして主要な処理系にkokaがある。 kokaは主にHaskellで書かれており、REPLはJSが使われている。 この記事はKoka言語ではなくkoka-lang/kokaのREPLの入門記事である。Kokaを知りたい方はThe Koka Bookを参照のこと。

処理系のビルド

$ git clone https://github.com/koka-lang/koka.git
$ cd koka
$ yarn # REPLを使うために必要

ここからHaskell関連のものをビルドする、特にalexをインストールしたりする。cabalとstackの2通りがある。 いずれかでalexをインストールする。

$ cabal install alex
# または
$ stack install alex

これでOK。 jakeでKoka REPLが起動する、が、stackを利用した場合にはbuild_with_stack=trueを毎度渡す必要がある。めんどいね。 またreadlineやlinenoiseなどをREPL内部で利用してないのでrlwrapを利用したほうが良いだろう。

$ rlwrap jake # ビルド時にstackを利用してたら`jake build_with_stack=true`
check for packages: text parsec
build: koka 0.9.0-dev (debug version)
build ok.
> out/debug/koka-0.9.0-dev  --outdir=out/lib -ilib -itest/algeff -itest/implicits -itest/ambients -itest/instance -itest/lib --core --checkcore
 _          _
| |        | |
| | __ ___ | | __ __ _
| |/ // _ \| |/ // _` | welcome to the koka interpreter
|   <| (_) |   <| (_| | version 0.9.0-dev (debug), Sep  8 2019
|_|\_\\___/|_|\_\\__,_| type :? for help

loading: std/core
> print("hello, world")
hello, world
>

あるいはビルドで生成されたkokaバイナリを叩けばいい。この場合謎の引数を渡す必要はない。

$ out/debug/koka-0.9.0-dev
 _          _
| |        | |
| | __ ___ | | __ __ _
| |/ // _ \| |/ // _` | welcome to the koka interpreter
|   <| (_) |   <| (_| | version 0.9.0-dev (debug), Sep  8 2019
|_|\_\\___/|_|\_\\__,_| type :? for help

loading: std/core
> print("hello, world")
hello, world
>

詳細は各ヘルプを見てほしい。

エフェクトの定義

Koka言語といえばAlgebraic Effects and Handlersが特筆すべき機能だが、実はREPLではエフェクトの定義ができない。ここはかなりのハマりポイントなので書いておく。

なんでやねん
> effect foo { fun foo(v : int): int } // REPLでは複数行にまたがる定義ができない…
interactive(1, 1): error: invalid syntax
 unexpected keyword effect
 expecting expression
>

Koka言語はファイルをモジュールという単位で利用する。そしてkoka REPLはlib/以下のファイルをモジュールとして読み込める。 モジュールは path/to/mod という、ライブラリディレクトリから相対パスのファイル名から拡張子 .kk を除いたものを識別子とする。 lib/path/to/mod.kk というファイルの先頭に module path/to/mod と書けばよい。 とりあえず lib/mod.kk というファイルに書いてみる。

module mod

public effect foo { // Kokaにはアクセス制御もあるよ
  fun foo(v : int) : int
}

そしてkoka REPLでモジュールを読み込む。

> :l mod
compile: lib/mod.kk
loading: std/core
check  : mod
modules:
  mod

> :t foo
(v : int) -> foo int

>

OK。ハンドラはもちろんfirst-class valueなので特に問題なく定義できる。

> val h = handler { foo(v) -> { println(v) ; resume(v + 1) } }
operator branch (h) foo: resume tail
h : forall<a,e> (action : () -> <foo,console|e> a) -> <console|e> a

> h { foo(3) }
operator branch (h) foo: resume tail
operator branch (h) foo: resume tail
3
4

>

OK2。

モジュール内での演算子の定義とREPLでの読み込み

KokaはScalaやHaskell、OCamlなどのように演算子を定義できる。 しかしモジュールで演算子を定義、利用すると怒られが発生する場合がある。 多分バグなので報告した。インターフェースファイルのパーザが記号に対応してないっぽい。 この怒られはインターフェースファイルを消去することで回避できる。

$ rm out/op.kki

コントリビューションチャンスです。


これで皆さんも快適にKokaが書けるようになったかもしれません。 メチャクチャ雑なVim syntax highlightがあるので、Vimmerはカラフルな世界でKokaを見ることができます。 Nymphium/vim-koka: vim utilities for koka language