Freer Effectsが、だいたいわかった: 11-3 KindSignatures拡張
目次
(0). 導入
-
Freeモナドの概要
- Freeモナドとは
- FreeモナドでReaderモナド、Writerモナドを構成する
- 存在型(ExistentialQuantification拡張)の解説
- 型シノニム族(TypeFamilies拡張)の解説
- データ族(TypeFamilies拡張)の解説
- 一般化代数データ型(GADTs拡張)の解説
- ランクN多相(RankNTypes拡張)の解説
-
FreeモナドとCoyoneda
- Coyonedaを使ってみる
- FreeモナドとCoyonedaを組み合わせる
- いろいろなモナドを構成する
-
Freerモナド(Operationalモナド)でいろいろなモナドを構成する
- FreeモナドとCoyonedaをまとめて、Freerモナドとする
- Readerモナド
- Writerモナド
- 状態モナド
- エラーモナド
-
モナドを混ぜ合わせる(閉じた型で)
- Freerモナドで、状態モナドとエラーモナドを混ぜ合わせる
- 両方のモナドを一度に処理する
- それぞれのモナドを、それぞれに処理する
- Freerモナドで、状態モナドとエラーモナドを混ぜ合わせる
- 存在型による拡張可能なデータ構造(Open Union)
- 追加の言語拡張
- ScopedTypeVariables拡張
- TypeOperators拡張
- KindSignatures拡張
- DataKinds拡張
- MultiParamTypeClasses拡張
- FlexibleInstances拡張
- OVERLAPSプラグマ
- Open Unionを型によって安全にする
- モナドを混ぜ合わせる(開いた型で)
- FreeモナドとOpen Unionを組み合わせる
- 状態モナドにエラーモナドを追加する
- Freer Effectsで、IOモナドなどの、既存のモナドを使用する
- 関数を保管しておくデータ構造による効率化
- いろいろなEffect
- 関数handleRelayなどを作成する
- NonDetについて、など
値に型付けできる型と、できない型
たとえば、型Boolや型Charは値を型付けできる。しかし、型Maybeは、そのままでは値を型付けできない。Maybe Charのように、型引数をひとつとる必要がある。型Eitherであれば、Either Bool Charのように、型引数をふたつとる必要がある。対話環境でみてみよう。
> False :: Bool
False
> 'c' :: Char
'c'
> Just 'c' :: Maybe Char
Just 'c'
> Left True :: Either Bool Char
Left True
型の型(種類)
型にも型がある。それを種類(kind)とよぶ。対話環境で型の種類をみてみよう。
> :type False
False :: Bool
> :kind Bool
Bool :: *
値Falseの型はBoolで、型Boolの種類は*だ。ここで、型Maybeの種類をみてみよう。
> :kind Maybe
Maybe :: * -> *
> :kind Bool
Bool :: *
> :kind Maybe Bool
Maybe Bool :: *
たとえば、(Int -> Int)型の関数にInt型の値を引数としてあたえると、Int型の値に評価される。それとおなじように、(* -> *)種の型構築子に*種の型をあたえると、*種の型になる。型引数をふたつとる型Eitherについてもみてみよう。
> :kind Either
Either :: * -> * -> *
> :kind Either Bool
Either Bool :: * -> *
> :kind Either Bool Char
Either Bool Char :: *
種推論
*種の型でないと値を型づけすることはできない。なので、たいていにおいて、型の種は機械的に推論できる。たとえば、つぎのような型宣言があったとする。
f :: a -> m a
すると、型aは*種の型であり、型mは(* -> *)種の型であることがわかる。
種推論がうまくいかない例
たとえば、自分の選んだ型だけに適用したい関数というものを考える。ここではリストとIOのみに使える関数funを考えよう。
module MyMonad (fun) where
class MyMonad m
fun :: (Monad m, MyMonad m) => m a -> m b -> m b
fun = (>>)
instance MyMonad []
instance MyMonad IO
クラスMyMonadを公開していないので、このクラスには、インスタンスを追加することができない。よって、関数funはリストとIOにしか適用できない、はずだ。対話環境に読み込んでみよう。
> :load MyMonad.hs
([]やIOに引数が足りないというエラーメッセージ)
class MyMonad mで、型変数mは値の型づけに使われていない。そのため、種推論がはたらかない。とりあえず、推論できない型は*種の型とされるようだ。うまく動くようにするには、まずファイルの先頭に言語拡張プラグマを追加する。
{-# LANGUAGE KindSignatures #-}
そのうえでクラスMyMonadの定義を、つぎのように変更する。
class MyMonad (m :: * -> *)
対話環境で試してみよう。
> :reload
> fun [1, 2, 3] [4, 5, 6]
[4,5,6,4,5,6,4,5,6]
> fun (print 8) (putStrLn "hello")
8
hello
> fun (Just 8) (Just 9)
(エラーになる)
まとめ
値には型があるように、型には種類がある。たいていにおいて、型の種類は機械的に推論できる。しかし、種推論がうまく働かないこともある。そのようなときには、KindSignatures拡張によって、型の種を明示的に注釈することができる。ここでは、人工的な例を挙げたが、ほかの言語拡張を利用して、いろいろと複雑なことをやりだすと、種注釈が必要な場面に、しばしば、つきあたることになる。