見出し画像

直和型の代わりにユニオン型を持つ関数型言語Cotton

伊藤 謙太朗(いとう けんたろう)

 伊藤さんは高校生のころから自分の理想のプログラミング言語を追求し,直和型ではなくユニオン型を採用した型システムを持つシンプルな静的型付けプログラミング言語Cottonを開発した.直和型とはプログラミング言語Rustのenumであったり,HaskellやOCamlのデータ型のように複数のコンストラクタを持つデータ型のことで,パターンマッチが使えるプログラミング言語によく見かける機能である.それに対して伊藤さんが大好きなユニオン型は,最近のTypeScriptやCrystal,Juliaなどで採用されている機能で,ユニオン型に便利さを感じているプログラマも徐々に増えてきている一方,静的型付け関数型言語の世界はユニオン型を採用する言語はまだ少ない.またあったとしても直和型やシールドクラスなどほかの機能の補助的な役割を担うのみにとどまっており,ユニオン型が持つ表現力の追求が行われていない.

 伊藤さんはユニオン型を持つ静的型付けプログラミング言語Cottonを設計し,コンパイラとランゲージサーバを開発し,以下の機能を実装した.

  • ユニオン型

  • 再帰的な型エイリアス

  • 網羅性チェック付きのパターンマッチ

  • 型推論

  • 演算子定義

  • 高階多相

  • オーバーロード

  • インタフェース

  • モジュールシステム

 たとえば,Cottonでフィボナッチ数を出力するコードは図-1のように書ける.

図-1  フィボナッチ数を出力するコード

 図-1の1~2行目で,右辺の関数に左辺の値を適用する演算子 . を定義している.forall { A, B }は,AとBが型変数であることを宣言している.この . 演算子によって,関数呼び出しをオブジェクト指向言語のメソッド呼び出しのように書くことができる.たとえば,図-1の2行目にあるf(a)はa.fと書くことができ,さらにprintln(fib(10))は図-1の12行目のように10.fib.printlnと書くことができる.図-1の4行目のinfixlは左結合を表し,優先順位を10と定義している.ちなみにこのCottonの.演算子は暗黙的にインポートされるモジュールpreludeで定義されているため,自分で図-1の1~4行目のようにわざわざ定義しなくても最初から使えるようになっている.

 図-1の7~9行はこれで1つのラムダ式で,引数に0が来たら0を返し,1が来たら1を返し,それ以外の値nが来たら(n-1)項のフィボナッチ数と (n-2)項のフィボナッチ数を足した値を返している.このようにパターンマッチとラムダ式が1種類の構文で表現されており,直感的に理解しやすいコードが書ける.

 次に,CottonでFizzBuzzを出力するコードは図-2のように書ける.

 FizzBuzzとは英語の言葉遊びで,1から100までの数字を画面に出力するプログラミングの問題だが,3の倍数のときは数字ではなく文字列Fizzを出力し,同様に5の倍数のときはBuzzを出力し,15の倍数のときはFizzBuzzと出力する.

図-2 FizzBuzzを出力するコード

 事前の準備として,1..101と書くと1,2,3,4~100までの数字のListを返せるように図-2の1~6行目で .. 演算子を定義している.また,図-2の8~10行目では,Listの各要素に関数を適用して新しいリストを返す関数mapを定義している.図-2の21行目では(1..101).mapと書いてそれらを呼び出している.

 図-2の12~17行目ではfizzbuzz関数を定義している.図-2の13行目では3の剰余と5の剰余がゼロかゼロ以外かの組合せでパターンマッチさせ,図-2の14行目のように両方ゼロのときはFizzBuzzを,図-2の15行目のように3の剰余のみがゼロのときはFizzを,図-2の16行目のように5の剰余のみがゼロの場合はBuzzを,両方とも非ゼロの場合はその数字を文字列に変換したものを返すようにしている.

 このようにCottonはシンプルな構文で自分自身を拡張できるように設計されている.

 最後に,ユニオン型の便利な側面としてエラーを表すときに有用であり,Cottonでエラーハンドリングを行うコードは図-3のように書ける.

図-3 エラーハンドリングするコード

 図-3の11~13行目にある ? はエラーだった場合にアーリーリターンをする記法で,この例ではエラー時の型がそれぞれ違う3つの関数に対するエラーハンドリングを行っている.図-3の9行目で定義しているdo_1_2_3の型ではユニオン型によって発生する可能性のあるエラーを具体的に示していて,このエラーに対して網羅性チェック付きのパターンマッチをすることも可能だ.Rustにも同じような記法があるが,Rustは直和型を採用しているためこのような場合にはenumやトレイトなどを使って3つのエラーの型が同一になるように調整する必要があり,エラーハンドリングが煩雑になってしまう.Cottonではこのようにユニオン型を使ってシンプルに書き表すことができる.

 CottonはGithub上で開発が続けられている.VSCode向けの拡張機能も実装されており,リアルタイムのシンタックスハイライトも可能で,マウスオーバーすると内部の型表現を出力する機能もある.Gitpod上で数クリックでPlaygroundとして実行できるオンライン環境も整備されているので,興味を持った方はぜひ触ってみていただきたい.Cottonの成果を広く公開することで,静的型付け関数型言語にユニオン型を採用する有用性を多くの人に知ってもらい,その後開発されるプログラミング言語の開発に影響を与えることを期待している.

(担当PM・執筆:竹迫 良範)

[関連URL]
https://github.com/nanikamado/cotton (開発中)

[統括PM追記] あるプログラミング言語がユーザコミュニティや開発コミュニティを巻き込んで「文化」にまで成長するには相当な時間を要するし,はっきり言ってしんどい.しかし言語設計に挑戦する,というよりは楽しむという「プログラミングの文化」を維持することは,プログラミングに関する柔らかい発想のためにとても重要である.伊藤さんは明確なアイディアをベースにきっちりと言語環境まで作り込んでいることからも分かるように,余裕を感じさせる開発を進めた.実際,それは今期のクリエータの中で,他プロジェクトに対する発言の多さで最も目立ったことにもつながった.

(2023年7月3日受付)
(2023年9月15日note公開)