0

我在实现代表嵌套数组中值结构的IsList实例时遇到了麻烦。GADT这是完整的代码:

{-# 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
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我部分理解为什么我有这个错误。但我想知道是否可以IsList为类型实现实例Val

4

2 回答 2

1

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,但它将项目和列表类型解耦。

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-03T14:03:51.570 回答
1

您通过仅存储 an在其类型中L ...包含 s 列表的事实来丢弃信息。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. 因为 thistoList有类型Val ('TList a) -> [Val a]它不能传递一个非列表,所以上面的实现不是部分的。您可以使用类型孔自己验证此类型:toList = _。您还可以验证(尝试)如下实现是否会产生类型错误:toList (I x) = undefined.

列表中的每个项目都必须具有相同的类型(例如,您不能将整数与单个列表中的列表混合),但问题中的原始代码也是如此。

于 2018-06-04T01:06:24.523 回答