來自Haskell新手的簡短版本:假設我有一個Container容器,其中Container有* -> *
種類。我希望把他們到另一個容器中,仍然使第二容器的原始類的實例像:Haskell - 容器和實例declration的容器
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
使用GADTs 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,但確實需要這種擴展?
只需翻轉像'data Container2 container a = Container2(container a)'這樣的參數即可。當你有'instance Iter f'時,它預計你可以爲元素'a'的迭代器寫'fa',而如果你有'type F = TransformedIter from',那麼'F a'不是元素的迭代器的'a',它是內部迭代器'a'的元素'to'的迭代器。 –
另外,這個類在Haskell中已經存在爲'Foldable'。特別是,任何'Foldable t'都有'toList :: t a - > [a]',它可以讓你構建你的迭代器。 –
謝謝@J。 Abrahamson,我明白類型排序有什麼問題。但是現在我又遇到了另一個錯誤,請參閱更新後的版本。 –