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