给定一个静态类型长度的列表(以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)
答案 0 :(得分:8)
例如:
instance HasLength (List el len) => HasLength (List el (Succ len)) where
length _ = 1 + length (undefined :: List el len)
注意:这需要ScopedTypeVariables
扩展名。
答案 1 :(得分:1)
如果您使用DataKinds
扩展程序,这会更加容易,这样您就可以将Natural
“宣传”为某种类型,从而使(推广)类型Zero
和{ {1}}更容易处理并消除像Succ 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
。)