

最近Haskellの勉強を初めて，適当にライブラリを読んでいるのですが，type演算子の用途について疑問があります．

例えば，以下の例ですと右辺がなく，何のシノニムになっているのか分かりません．

<https://github.com/RaphaelJ/friday/blob/master/src/Vision/Image/Class.hs#L93>

[code]

    class Storable (ImagePixel i) => MaskedImage i where
        type ImagePixel i
    
[/code]

また，以下の例では，左辺 ImagePixel (Manifest p) のほうが，右辺 p よりも複雑になっていて，  
シノニムを使う理由がよく分かりません．

<https://github.com/RaphaelJ/friday/blob/master/src/Vision/Image/Type.hs#L52>

[code]

    instance Storable p => MaskedImage (Manifest p) where
        type ImagePixel (Manifest p) = p
    
[/code]

type演算子には，型シノニム以外の使い方があるのでしょうか？


CC BY-SA 3.0
2015-05-20T15:18:16.290
10429
2015-05-22T05:50:18.683
9817
question
haskell
Haskellのtype演算子に型シノニム以外の使い方はありますか？


`class`や`instance`宣言中に現れる`type`や`data`は **Type Families（型族）**
というGHC拡張で、トップレベルに現れる`type`とは少し異なる機能を提供しています。  
型族を有効にするには、pragmaとして`TypeFamilies`を指定します（リンク先のソースコード先頭で宣言されています）。

Cf. <https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/type-
families.html>

## 型関数

`class`宣言と`instance`宣言は普段の型クラス同様に対応しています。

普段、`class`宣言で「メソッド、その型、デフォルト実装」が与えられると思います。型族を用いると、言わばその「型レベル版」も宣言できる様になります。それが`type`を用いた型関数の宣言です。  
つまりは「型関数、その種(kind)、デフォルト型」が定義できます。

その確認のため、trivialな例を出します:

[code]

    class Hoge i where
        type Fuga i :: *         -- 種(kind)の明示
        type Fuga i = ()         -- デフォルト型
    
        piyo :: Fuga i -> Fuga i -- `Fuga i` の使用
        piyo = id                -- デフォルト実装
    
    instance Hoge Int where
        type Fuga Int = Maybe Int
        piyo mn = fmap succ mn
    
    instance Hoge Double where
        type Fuga Double = [Double]
        piyo ls = ls ++ ls
    
[/code]

`piyo`がメソッドで、`Fuga`が型関数です。似た様に宣言できることが分かると思います。また、`Fuga i` を型として使うことも確認できます。

## 具体例

まず`class`宣言を見てみます:

[code]

    class Storable (ImagePixel i) => MaskedImage i where
        type ImagePixel i
    
[/code]

この宣言から分かることは、

  * 型クラス`MaskedImage`を定義している
  * `i`は`MaskedImage`のインスタンスを表す型変数
  * `ImagePixel i`は`Storable`のインスタンスでなければならない
  * `ImagePixel i`はinstance宣言で定義される型シノニム
  * kindは省略されている
  * デフォルト型は定義されていない

といったところでしょうか。  
次に`instance`宣言を見てみます:

[code]

    instance Storable p => MaskedImage (Manifest p) where
        type ImagePixel (Manifest p) = p
    
[/code]

この`instance`宣言から分かることは、

  * `Manifest p`は`MaskedImage`のインスタンス（たまたまインスタンスにも型変数`p`が含まれています）
  * `ImagePixel (Manifest p)`は`p`の型シノニム
  * `p`は`Storable`のインスタンスでなければならない

型チェックが通ればこの`instance`宣言はvalidと言えます。  
ただ、`Storable p`についてもう少し説明が要るかもしれません。

## 確認

以下、この`instance`定義がvalidであることを簡単に確認します。

`Manifest p`を`MaskedImage`のインスタンスにするため、

  * `class`を`instance`に書き換え
  * `i`を`Manifest p`に機械的に置き換え

によって、以下が得られます:

[code]

    instance Storable (ImagePixel (Manifest p)) => MaskedImage (Manifest p) where
        type ImagePixel (Manifest p)
    
[/code]

ここで開発者は`ImagePixel (Manifest p)`は`p`の型シノニムであると定義したのでした:

[code]

    instance Storable (ImagePixel (Manifest p)) => MaskedImage (Manifest p) where
        type ImagePixel (Manifest p) = p
    
[/code]

この型シノニムの定義通り、`ImagePixel (Manifest p)`は`p`に置き換えられるため、以下が得られます:

[code]

    instance Storable p => MaskedImage (Manifest p) where
        type ImagePixel (Manifest p) = p
    
[/code]


CC BY-SA 3.0
2015-05-21T18:49:18.277
10475
2015-05-22T05:50:18.683
2015-05-22T05:50:18.683
3636
3636
10429
answer