首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >HList带DataKinds,种类不可推广

HList带DataKinds,种类不可推广
EN

Stack Overflow用户
提问于 2015-01-19 03:37:52
回答 1查看 299关注 0票数 2

我有这个代码片段,它使用了大量的GHC扩展:

代码语言:javascript
复制
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}

import GHC.Exts (Constraint)

data HList :: [*] -> * where
    Nil  :: HList '[]
    Cons :: a -> HList l -> HList (a ': l)

type family All (p :: * -> Constraint) (xs :: HList [*]) :: Constraint where
    All p Nil = ()
    All p (Cons x xs) = (p x, All p xs)

GHC抱怨说:

代码语言:javascript
复制
 ‘HList’ of kind ‘[*] -> *’ is not promotable
    In the kind ‘HList [*]’

为什么我不能把HList推广到一种类型呢?使用GHC、7.8.27.11,我得到了同样的错误。

当然,使用内置的'[]运行得很好:

代码语言:javascript
复制
type family All (p :: * -> Constraint) (xs :: [*]) :: Constraint where
    All p '[]       = ()
    All p (x ': xs) = (p x, All p xs)

我想使用自己的HList而不是'[],因为实际的HList支持附加,如下所示:

代码语言:javascript
复制
type family (:++:) (xs :: [*]) (ys :: [*]) where
    '[] :++:  ys = ys
     xs :++: '[] = xs
    (x ': xs) :++: ys = x ': (xs :++: ys)

data HList :: [*] -> * where
    Nil  :: HList '[]
    Cons :: a -> HList l -> HList (a ': l)
    App  :: Hlist a -> HList b -> HList (a :++: b)

编辑:主要目标是让GHC推断

代码语言:javascript
复制
(All p xs, All p ys) ==> All p (xs :++: ys)

这样我才能写

代码语言:javascript
复制
data Dict :: Constraint -> * where
    Dict :: c => Dict c

witness :: Dict (All p xs) -> Dict (All p ys) -> Dict (All p (xs :++: ys))
witness Dict Dict = Dict

我曾希望为附加类型级别的列表添加一个显式表示会帮助我实现这一点。是否有其他方法使GHC相信上述情况?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-01-19 14:14:34

现在我明白了,问题是如何编写(All p xs, All p ys) => All p (xs :++: ys)的证明。答案是,通过归纳,当然!

我们真正想要编写的函数的类型是

代码语言:javascript
复制
allAppend :: (p :: Constraint) -> (xs :: [*]) -> (ys :: [*]) 
          -> (All p xs, All p ys) -> All p (xs :++: ys)

但是Haskell没有依赖类型。“伪造”依赖类型通常意味着有一个证人带着一种类型存在的证据。这使事情有些乏味,但目前没有其他方法。我们已经有了一个xs列表的目击者--这正是HList xs。对于约束,我们将使用

代码语言:javascript
复制
data Dict p where Dict :: p => Dict p

然后,我们可以将隐含写成一个简单的函数:

代码语言:javascript
复制
type (==>) a b = Dict a -> Dict b 

所以我们的类型变成:

代码语言:javascript
复制
allAppend :: Proxy p -> HList xs -> HList ys 
          -> (All p xs, All p ys) ==> (All p (xs :++: ys))

函数的主体非常简单--注意allAppend中的每个模式是如何匹配:++:定义中的每个模式的。

代码语言:javascript
复制
allAppend _ Nil _  Dict = Dict  
allAppend _ _  Nil Dict = Dict 
allAppend p (Cons _ xs) ys@(Cons _ _) Dict = 
  case allAppend p xs ys Dict of Dict -> Dict 

与此相反的是,All p (xs :++: ys) => (All p xs, All p ys)也适用。事实上,函数的定义是相同的。

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

https://stackoverflow.com/questions/28017635

复制
相关文章

相似问题

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