0

* -> *Haskell 初心者からの短いバージョン: Container にkindがあるクラス Container があるとします。それを別のコンテナに入れて、2番目のコンテナを元のクラスのインスタンスにしたい:

data Container2 a container = Container2 (container a)

instance Container (Conrainer2 a) where ...

しかし、GHC は常に次のようなエラーを生成するため、これは不可能のようです。

Kind mis-match

    The first argument of `Container' should have kind `* -> *',
    but `Container2 a' has kind `(* -> *) -> *'

それを回避することは可能ですか?

長いバージョン: Java で反復子インターフェイスをモデル化する次のコードをいじっています。

module Main where

data NextResult a iter = Stop | More a (iter a)

class Iter iter where
  next :: iter a -> NextResult a iter

-- Convert iterator to a list
toList :: (Iter c) => c a -> [a]
toList iter = case next iter of
  Stop -> []
  More value iter2 -> value : toList iter2 

-- List itself is iterator
instance Iter [] where
  next [] = Stop
  next (x:xs) = More x xs

main = let iter = [1,2,3,4,5] in print $ toList iter

GHC 7.4.1 では、これは予想される をコンパイルして出力し1 2 3 4 5ます。ここで、関数と反復子から新しい反復子を構築する変換反復子を定義したいと考えています。そのために、次の行を追加しました。

data TransformedIter from to iter = TransformedIter (from->to) (iter from)

instance Iter (TransformedIter from to) where
  next (TransformedIter f iter) = case next iter of
    Stop -> Stop
    More value iter2 -> More (f value) (TransformedIter f iter2)

しかし、それはエラーを生成しました:

Main.hs:21:16:
    Kind mis-match
    The first argument of `Iter' should have kind `* -> *',
    but `TransformedIter from to' has kind `(* -> *) -> *'
    In the instance declaration for `Iter (TransformedIter from to)'

私はそれを回避しようとしましたが、結果は常に何らかの種類のエラーでした。では、Haskell でそのような変換をモデル化するにはどうすればよいでしょうか?

アップデート

インスタンス宣言の仕組みを誤解していました。以下の提案に基づいて、TransformedIter タイプの順序を反転させ、最終的には次のようになりました。

module Main where

data NextResult a iter = Stop | More a (iter a)

class Iter iter where
  next :: iter a -> NextResult a iter

toList :: (Iter c) => c a -> [a]
toList iter = case next iter of
  Stop -> []
  More value iter2 -> value : toList iter2 

instance Iter [] where
  next [] = Stop
  next (x:xs) = More x xs

main = let iter = [1,2,3,4,5] in print $ toList iter

data TransformedIter iter from to = TransformedIter (from->to) (iter from)

instance Iter (TransformedIter iter from) where
  next (TransformedIter f iter) = case next iter of
    Stop -> Stop
    More value iter2 -> More (f value) (TransformedIter f iter2)

ただし、別のエラーが発生しました:

Main.hs:22:40:
    No instance for (Iter iter)
      arising from a use of `next'
    In the expression: next iter
    In the expression:
      case next iter of {
        Stop -> Stop
        More value iter2 -> More (f value) (TransformedIter f iter2) }
    In an equation for `next':
        next (TransformedIter f iter)
          = case next iter of {
              Stop -> Stop
              More value iter2 -> More (f value) (TransformedIter f iter2) }

インスタンス宣言を次のように変更しました。

instance Iter (Iter iter => TransformedIter iter from) where

それは別のエラーを生成しました:

Main.hs:21:10:
    Illegal instance declaration for `Iter
                                        (Iter iter => TransformedIter iter from)'
      (All instance types must be of the form (T a1 ... an)
       where a1 ... an are *distinct type variables*,
       and each type variable appears at most once in the instance head.
       Use -XFlexibleInstances if you want to disable this.)
    In the instance declaration for `Iter (Iter iter =>
                                           TransformedIter iter from)'

-XFlexibleInstances を追加した後、次のようになりました。

Main.hs:21:10:
    Illegal polymorphic or qualified type:
      Iter iter => TransformedIter iter from
    In the instance declaration for `Iter (Iter iter =>
                                           TransformedIter iter from)'

そのため、TransformedIter を Iter のインスタンスとして宣言する方法がまだわかりません。手がかりはありますか?

更新 2

GADT の GHC 拡張機能を使用して、TransformedIter を定義することができました。

module Main where

data NextResult a iter = Stop | More a (iter a)

class Iter iter where
  next :: iter a -> NextResult a iter

toList :: (Iter c) => c a -> [a]
toList iter = case next iter of
  Stop -> []
  More value iter2 -> value : toList iter2 

instance Iter [] where
  next [] = Stop
  next (x:xs) = More x xs

data TransformedIter iter from to where
  TransformedIter :: Iter iter => 
                     (from->to) -> (iter from) -> TransformedIter iter from to

instance Iter (TransformedIter iter from) where
  next (TransformedIter f iter) = case next iter of
    Stop -> Stop
    More value iter2 -> More (f value) (TransformedIter f iter2)

twice = (*) 2

main = let iter = TransformedIter twice [1,2,3,4,5] in print $ toList iter

これにより、予想される 2 4 6 8 10 がコンパイルおよび出力されます。しかし、この拡張機能は本当に必要なのでしょうか?

4

1 に答える 1

1

答えはJ. Abrahamsonのコメントで与えられました。これで、GHC 拡張機能を使用せずに動作するバージョンがついに完成しました (以前、インスタンス宣言のコンテキストに間違った構文を使用していました)。

module Main where

data NextResult a iter = Stop | More a (iter a)

class Iter iter where
  next :: iter a -> NextResult a iter

toList :: (Iter c) => c a -> [a]
toList iter = case next iter of
  Stop -> []
  More value iter2 -> value : toList iter2 

instance Iter [] where
  next [] = Stop
  next (x:xs) = More x xs

data TransformedIter iter from to = TransformedIter (from->to) (iter from)

instance Iter iter => Iter (TransformedIter iter from) where
  next (TransformedIter f iter) = case next iter of
    Stop -> Stop
    More value iter2 -> More (f value) (TransformedIter f iter2)

twice = (*) 2

main = let iter = TransformedIter twice [1,2,3,4,5] in print $ toList iter

それは 2 4 6 8 10 を出力します

于 2014-11-21T22:15:00.227 に答える