LoginSignup
5
0

More than 5 years have passed since last update.

Freer Effectsが、だいたいわかった: 11-3 KindSignatures拡張

Last updated at Posted at 2017-10-23

Freer Effectsが、だいたいわかった: 11-3 KindSignatures拡張

目次

(0). 導入

  1. Freeモナドの概要
    • Freeモナドとは
    • FreeモナドでReaderモナド、Writerモナドを構成する
  2. 存在型(ExistentialQuantification拡張)の解説
  3. 型シノニム族(TypeFamilies拡張)の解説
  4. データ族(TypeFamilies拡張)の解説
  5. 一般化代数データ型(GADTs拡張)の解説
  6. ランクN多相(RankNTypes拡張)の解説
  7. FreeモナドとCoyoneda
    • Coyonedaを使ってみる
    • FreeモナドとCoyonedaを組み合わせる
      • いろいろなモナドを構成する
  8. Freerモナド(Operationalモナド)でいろいろなモナドを構成する
    • FreeモナドとCoyonedaをまとめて、Freerモナドとする
    • Readerモナド
    • Writerモナド
    • 状態モナド
    • エラーモナド
  9. モナドを混ぜ合わせる(閉じた型で)
    • Freerモナドで、状態モナドとエラーモナドを混ぜ合わせる
      • 両方のモナドを一度に処理する
      • それぞれのモナドを、それぞれに処理する
  10. 存在型による拡張可能なデータ構造(Open Union)
  11. 追加の言語拡張
    1. ScopedTypeVariables拡張
    2. TypeOperators拡張
    3. KindSignatures拡張
    4. DataKinds拡張
    5. MultiParamTypeClasses拡張
    6. FlexibleInstances拡張
    7. OVERLAPSプラグマ
  12. Open Unionを型によって安全にする
  13. モナドを混ぜ合わせる(開いた型で)
    • FreeモナドとOpen Unionを組み合わせる
    • 状態モナドにエラーモナドを追加する
  14. Freer Effectsで、IOモナドなどの、既存のモナドを使用する
  15. 関数を保管しておくデータ構造による効率化
  16. いろいろな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を考えよう。

MyMonad.hs
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は値の型づけに使われていない。そのため、種推論がはたらかない。とりあえず、推論できない型は*種の型とされるようだ。うまく動くようにするには、まずファイルの先頭に言語拡張プラグマを追加する。

MyMonad.hs
{-# LANGUAGE KindSignatures #-}

そのうえでクラスMyMonadの定義を、つぎのように変更する。

MyMonad.hs
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拡張によって、型の種を明示的に注釈することができる。ここでは、人工的な例を挙げたが、ほかの言語拡張を利用して、いろいろと複雑なことをやりだすと、種注釈が必要な場面に、しばしば、つきあたることになる。

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0