我正在学习Haskell,并希望编写函数来递归处理任意深度嵌套的列表。
例如,我想写recurReverse
,在基本情况下,就像内置reverse
一样,但是当传递嵌套列表时,reverse
递归地列出了子列表的所有元素:
recurReverse [1,2]
>> [2,1]
recurReverse [[1],[2],[3,4]]
>> [[4,3],[2],[1]]
recurReverse [[[1,2]]]
>> [[[2,1]]]
目前我已经基本reverse
向下:
rev [] = []
rev (h:t) = rev t ++ [h]
但我需要更多 - 在头部h
也是一个列表(与LISP意义上的原子相对)的情况下,我希望能够{{ 1}} reverse
并返回h
之类的内容。当我尝试这样做时,我收到编译错误,说我不能rev t ++ [rev h]
,因为rev h
属于rev
类型,但我试图在类型上调用它[t] -> [t]
,这是有道理的。我怎么能绕过这个?
答案 0 :(得分:7)
与LISP意义上的原子相反
嗯,Haskell中没有这样的东西。任何你不知道先验的类型(你不能,如果你正在对类型进行递归)可能是一个列表本身。没有原子性的概念,“not-list-being”你可以用作这种递归的基本案例。
也就是说,除非你明确区分。这可以在Haskell中很好地完成,使用GADT:
data Nest t where
Egg :: t -> Nest t
Nest :: [Nest t] -> Nest [t]
nestReverse :: Nest t -> Nest t
nestReverse (Egg x) = Egg x
nestReverse (Nest xs) = Nest . reverse $ map nestReverse xs
如果你不喜欢这个......好吧,还有另外一种方法,但它被认为是丑陋的/非Haskell-ish。
class Atomeous l where
recurReverse :: l -> l
instance {-# OVERLAPPABLE #-} Atomeous l where
recurReverse = id
instance Atomeous l => Atomeous [l] where
recurReverse = reverse . map recurReverse
现在,recurReverse
有您的预期行为。第一个例子是“原子”类型;因为它被标记为OVERLAPPABLE
,所以如果编译器找不到“更好的”,它将只使用这个实例 - 这对于列表来说是正确的;这些会对所有元素进行递归调用。