新しいパラダイムの理解を開拓すべく、Koka に手を出しています。
Koka の本丸は、その名(Koka = "効果")が示す通り Effect system なのですが、基本の構文をいじるだけで、そこまでたどり着けない始末。
一方で、これまでの知識が手掛かり足掛かりとなって、少ない情報であっても前に進むことができます。
例えば、struct 、いわゆる構造体が Koka にもあります。
struct person age : int name : string
これは糖衣構文で実態は次のコードと同じです。
type person
Person
age : int
name : string
こうなると、むしろ逆に「 Person がコンストラクタ」とわかり、勘が利くようになります。
このコードを person.kk というファイルに保存して、使ってみます。
まずは REPL を起動。
$ koka _ _ | | | | | | _ ___ | | _ __ _ welcome to the koka interactive compiler | |/ / _ \| |/ / _' | version 3.2.3, Mar 18 2026, libc arm64 (clang) | ( (_) | ( (_| | output dir: .koka/v3.2.3/clang-debug-69e713 |_|\_\___/|_|\_\__,_| type :? for help, and :q to quit
:l コマンドでファイルを読み込みます。
> :l person parse : .../person.kk check : person
コンストラクタ Person で値を作り name で文字列の値を取り出します。
> Person(20, "Alice").name linking : person/@main created : .koka/v3.2.3/clang-debug-69e713/person__main Alice
(実行するごとに linking, created が表示されますが、以降は省略します)
ここでちょっと不自然なことをしました。
実は person をコンソールへ出力する手段がないためこのままではエラーになってしまいます。
> Person(20, "Alice") ^ /@virtual/person/@main.kk(1, 3): type error: types do not match context : (Person(20, "Alice") ).println term : (Person(20, "Alice") ) inferred type: person/person expected type: string
エラーメッセージを見ると println が定義されていればよさそうな気配です。
リンクをたどってライブラリのドキュメントへ行くと、println には 2 種類あることがわかります。
一方は引数の型が string なのでおそらく使えません。
fun string/println( s : string ) : console ()
もう一方は引数の型がパラメータになっています。 おそらくこっちを多重定義すればいけるはず。
fun default/show/print( x : a, ?show : (a) -> <console|e> string ) : <console|e> ()
person.kk に次の定義を追加します。
文字列の連結がわかってないので、ただ順番に出力しました。
fun default/show/println(p : person)
print(p.name)
print("(")
print(p.age)
println(")")
ここで print(p.age) と print を使って数値を出力しています。
REPL でも確認できますが、これもまた多重定義されているのだと思います。
> Person(20, "Alice").age 20
ファイルを読み込み直し、実行です。
> Person(20, "Alice") Alice(20)
明示的に関数を適用できることもできます。
> println(Person(20, "Alice")) Alice(20)
よさそうです。
ところで。
エラーメッセージには context : (Person(20, "Alice") ).println と出力されていました。
これは dot selection と呼ばれる糖衣構文の模様。
s.encode(3).count.println は、すなわち println(count(encode(s,3)))) と同じ。
やってみます。
> Person(20, "Alice").println Alice(20)
ドットをパイプに置き換えると、Elixir の構文との類似も見えてきます。
これもちょっとやってみます。
defmodule Person do defstruct [:age, :name] defimpl String.Chars do def to_string(person) do "#{person.name}(#{person.age})" end end end
person.ex という名前でファイルに保存して iex を起動します。
iex(1)> c "person.ex"
[Person, String.Chars.Person]
iex(2)> %Person{age: 20, name: "Alice"} |> IO.puts()
Alice(20)
背景は異なるかもしれませんが、意図するものは近いので、これで覚えることを減らせます。
…思い返してみると、新しい言語を覚えるときはいつもこんなことをやっている気がします。 だからこそ、勘が利かなくなる領域に触れたときに、これはいったい何なのかと好奇心が立ち上がってくるのだと思います。
Koka に触れて数日、まだそこまで進めていないのが、もどかしくもあり楽しみでもあり。