我在实现GADT
的IsList
实例时遇到了麻烦,它表示嵌套数组中的值的结构。下面是完整的代码:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
import GHC.Exts (IsList (..))
data ValType = TInt | TList
data Val (t :: ValType) where
I :: Int -> Val 'TInt
L :: [Val a] -> Val 'TList
instance Show (Val t) where
show (I i) = "I " ++ show i
show (L a) = show a
instance IsList (Val 'TList) where
type Item (Val 'TList) = forall a . Val a
fromList = L
toList = error "Not implemented!"
我看到这样的错误:
GADT.hs:20:10: error:
• Illegal polymorphic type: forall (a :: ValType). Val a
• In the type instance declaration for ‘Item’
In the instance declaration for ‘IsList (Val 'TList)’
|
20 | type Item (Val 'TList) = forall a . Val a
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
我部分理解了为什么我会有这个错误。但是我想知道是否可以为Val
类型实现IsList
实例?
发布于 2018-06-03 22:03:52
IsList
似乎不适合这样做,因为项类型Item l
必须由列表类型l
确定。但是,可以使用RebindableSyntax
进一步推送列表的重载
{-# LANGUAGE RebindableSyntax, OverloadedLists #-}
fromListN :: _Int -> [Val a] -> Val 'TList
fromListN _ = L
现在[[I 3, I 2]]
对fromListN 1 [fromListN 2 [I 3, I 2]]
来说是糖,L [L [I 3, I 2]]
的缩写。
我们可以使用像IsList
这样的类型类来保持原来的行为,但是它将item和list类型解耦。
class IsList item l where
fromListN :: Int -> [item] -> l
instance IsList (Val a) (Val 'TList) where
fromListN _ = L
instance (item ~ item') => IsList item [item'] where
fromListN _ = id
发布于 2018-06-04 09:06:25
如果只存储L ...
在其类型中包含Val a
列表这一事实,那么您就是在丢弃信息。如果你保留这些信息
data ValType = TInt | TList ValType
data Val (t :: ValType) where
I :: Int -> Val 'TInt
L :: [Val a] -> Val ('TList a)
然后就可以从标准库中为IsList
类型类实现一个实例:
instance IsList (Val ('TList a)) where
type Item (Val ('TList a)) = Val a
fromList = L
toList (L xs) = xs
-- (For completeness, this example requires the OverloadedLists extension)
example :: String
example = show ([I 1, I 2, I 3] :: Val ('TList TInt))
另请注意,您可以实现toList
。由于此toList
的类型为Val ('TList a) -> [Val a]
,因此不能向其传递非list,因此上面的实现不是部分的。您可以通过使用类型hole:toList = _
自己验证此类型。您还可以验证如下所示的(尝试)实现是否会产生类型错误:toList (I x) = undefined
。
列表中的每一项都必须具有相同的类型(例如,您不能在单个列表中混合使用整数和列表),但问题中的原始代码也是如此。
https://stackoverflow.com/questions/50665537
复制相似问题