首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >GADT的“IsList”实例

GADT的“IsList”实例
EN

Stack Overflow用户
提问于 2018-06-03 18:47:14
回答 2查看 112关注 0票数 0

我在实现GADTIsList实例时遇到了麻烦,它表示嵌套数组中的值的结构。下面是完整的代码:

代码语言:javascript
复制
{-# 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!"

我看到这样的错误:

代码语言:javascript
复制
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实例?

EN

回答 2

Stack Overflow用户

发布于 2018-06-03 22:03:52

IsList似乎不适合这样做,因为项类型Item l必须由列表类型l确定。但是,可以使用RebindableSyntax进一步推送列表的重载

代码语言:javascript
复制
{-# 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类型解耦。

代码语言:javascript
复制
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
票数 1
EN

Stack Overflow用户

发布于 2018-06-04 09:06:25

如果只存储L ...在其类型中包含Val a列表这一事实,那么您就是在丢弃信息。如果你保留这些信息

代码语言:javascript
复制
data ValType = TInt | TList ValType

data Val (t :: ValType) where
    I :: Int     -> Val 'TInt
    L :: [Val a] -> Val ('TList a)

然后就可以从标准库中为IsList类型类实现一个实例:

代码语言:javascript
复制
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

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50665537

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档