Posted at

koka-lang/koka REPL超入門

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

さて、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 というファイルに書いてみる。


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