【问题标题】:Write length function for list with statically typed length为具有静态类型长度的列表编写长度函数
【发布时间】:2012-11-25 22:00:07
【问题描述】:

给定一个静态类型长度的列表(以this 为例):

data Zero

data Succ nat

data List el len where
    Nil  ::                      List el Zero
    Cons :: el -> List el len -> List el (Succ len)

是否可以编写一个长度函数,使用静态类型而不是通常的递归来计算长度?

到目前为止,我的努力使我得出的结论是,这是不可能的,因为它需要“取消”类型信息才能重复出现:

class HasLength a where
    length :: a -> Natural

instance HasLength (List el Zero) where
    length _ = 0

instance HasLength (List el (Succ len)) where
    length _ = 1 + *how to recur on type of len*

但是,我才刚刚开始了解类型的所有可能魔法,所以我知道我无法构想解决方案并不意味着没有解决方案。

更新

由于长度返回自然,我错误地写了length _ = 1 + ...。正确的实例(使用下面给出的答案)是

instance HasLength (List el len) => HasLength (List el (Succ len)) where
    length _ = succ $ length (undefined :: List el len)

【问题讨论】:

    标签: haskell types


    【解决方案1】:

    例如这样:

    instance HasLength (List el len) => HasLength (List el (Succ len)) where
        length _ = 1 + length (undefined :: List el len)
    

    注意:这需要ScopedTypeVariables 扩展名。

    【讨论】:

      【解决方案2】:

      如果您使用 DataKinds 扩展,这将更容易,这将允许您将 Natural '提升'为一种,这使得(提升)类型 ZeroSucc n 更易于处理并消除像Succ Char 这样的废话。有几种方法可以解决,但要紧贴您的文字:

      {-#LANGUAGE GADTs, DataKinds, StandaloneDeriving  #-}
      data Natural = Zero | Succ Natural deriving (Show,Eq,Ord)
      
      data List el len  where
          Nil  ::                      List el Zero 
          Cons :: el -> List el len -> List el (Succ len) 
      
      deriving instance Show el => Show (List el len)
      
      class HasLength f where len ::  f n -> Natural
      
      instance HasLength (List el) where
          len Nil = Zero
          len (Cons _ xs) = Succ (len xs)
      

      (我也使用了StandaloneDeriving,在这种情况下需要自动派生Show。)

      【讨论】:

      • 谢谢applicative,你是对的;这干净多了。但是,当我尝试运行它时得到以下信息:Kind mis-match The first argument of HasLength should have kind * -> *, but List el has kind Natural -> * In the instance declaration for HasLength (List el) 恐怕我不知道对此的适当修复。似乎指定 HasLength 的参数应该有一种 Natural -> * 会使其不必要地具体,但我不确定。有什么建议吗? :)
      • 嗯,可能是 ghc 版本——这些东西是自 ghc-7.4 以来的新内容。或者,也许我错过了一些东西。您可以向HasLength 添加一个专门的签名。但是,对于您的长度索引列表和常规 haskell 列表的实例,这对我来说运行良好,无论是 ghc-7.4 还是 ghc-7.6 hpaste.org/78395
      • 啊哈,你的 hpaste 清除了它。我缺乏 PolyKinds 编译指示。非常感谢!
      猜你喜欢
      • 2010-09-27
      • 2021-01-27
      • 2011-11-27
      • 1970-01-01
      • 2022-09-23
      • 2016-05-30
      • 2015-01-17
      • 1970-01-01
      • 2015-06-08
      相关资源
      最近更新 更多