エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

Koka を手探りする

新しいパラダイムの理解を開拓すべく、Koka に手を出しています。

koka-lang.github.io

Koka の本丸は、その名(Koka = "効果")が示す通り Effect system なのですが、基本の構文をいじるだけで、そこまでたどり着けない始末。

en.wikipedia.org

一方で、これまでの知識が手掛かり足掛かりとなって、少ない情報であっても前に進むことができます。

例えば、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 種類あることがわかります。

koka-lang.github.io

一方は引数の型が 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 に触れて数日、まだそこまで進めていないのが、もどかしくもあり楽しみでもあり。