TypeFamilyDependencies の実用的な例を考える
FunctionalDependencies
という GHC 言語拡張がある.Haskell Wiki によると,
Functional dependencies are used to constrain the parameters of type classes.
と書かれているが,これはどういうことか.
Haskell Language Report で定められた範囲では,型クラスに与えられるパラメータは1つに限られるが,MultiParamTypeClasses
を用いると,複数のパラメータを与えることができる.この際に,パラメータとして与えられた (複数の) 型の間の関係性に制限を加えることができるのが,FunctionalDependencies
なのであった.恐らく多くの人が初めて目にするのは,mtl
package の MonadReader
の定義なのではないだろうか.| m -> r
というのがそれである.
class Monad m => MonadReader r m | m -> r where
...
さて,GHC 8 から TypeFamilyDependencies
という GHC 言語拡張が追加された.これについては既に lotz 先生が『型族が単射だと嬉しい理由』という記事を書いていらっしゃるのだが,(氏には失礼ながら) 少しばかりわざとらしい例だと感じたので,もう少し実務的な例を引き合いに出して,有用性を示したいと思う.
Template Haskell でコード中に JSON を埋め込んだりコンパイル時にファイルから型安全に読み込んだりする
Template Haskell でコンパイル時 FizzBuzz
数ヶ月前に Twitter で,コンパイル時に FizzBuzz を計算して,実行時には計算された文字列を出力をするだけ,というコンパイル時 FizzBuzz を何かの言語でやっているのを見かけた.元ネタは江添さんがC++で書いたものらしい.インスピレーションを受けて,Haskell で書いてはみたが,簡単すぎて全然おもしろくなくなってしまった.
Type-level TypeScript
この記事は CAMPHOR- Advent Calendar 2017 の21日目の記事です.
12月といえば,万人受けしなさそうなネタでブログを書いては「はてブが付かねえ」と文句を言う季節だが,今年もそういう方針で,TypeScript での型レヴェル計算について書く.型レヴェルでの自然数などが定義できると,リストに型レヴェルで長さを付けることができて,空リストの先頭の要素を取ろうとしてランタイムで落ちる,という悲劇が生じる可能性をコンパイル時に排除できてとても嬉しい*1.
なお,使用している TypeScript のヴァージョンは,少し古くて 2.4.1 である.これは,手元でたまたま 2.6 系のプロジェクトと 2.4 系のプロジェクトがあったのだが,2.6 系だと型推論が停止しない (tsc
が "Maximum call stack size exceeded" で死ぬ) ことに気付き,悲しい気持ちになったからである.