Hello Haskellers和Haskellettes,
在阅读http://learnyouahaskell.com/时,我的一位朋友提出了一个问题:
在Haskell中是否可以编写一个递归函数,如果所有子子列表都为空,则该函数给出True。我的第一个猜测是 - 应该是 - 但是我在编写类型注释时遇到了一个大问题。
他试过像这样的东西nullRec l = if null l
then True
else if [] `elem` l
then nullRec (head [l]) && nullRec (tail l)
else False
是 - 不工作 - : - )
我想出了像这样的东西但后者对于这个问题听起来有点过分。 你有什么想法 - 在这样一个阳光明媚的星期天; - )
提前致谢
作为对所有评论的反应 - 这是我想添加的糟糕风格
这只是一个实验!
请勿在家中尝试此操作!; - )
答案 0 :(得分:5)
类型类怎么样?
{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}
class NullRec a where
nullRec :: a -> Bool
instance NullRec a => NullRec [a] where
nullRec [] = True
nullRec ls = all nullRec ls
instance NullRec a where
nullRec _ = False
main = print . nullRec $ ([[[[()]]]] :: [[[[()]]]])
答案 1 :(得分:4)
由于以下原因,仅使用参数多态无法实现这一点。
考虑以下这些值:
x = [8] :: [Int]
y = [3.0] :: [Double]
z = [[]] :: [[Int]]
显然,您希望自己的功能同时适用于x
和y
,因此其类型必须为null1 :: [a] -> Bool
。 (有人可以帮助我使这个论点看起来正式吗?我怎样才能证明这是与[Int] -> Bool
和[Double] -> Bool
统一的唯一最具特色的无上下文类型?这个关系是否有名称?类型之间?)
现在,如果您有这种类型,那么null1 z
将等于null1 x
,因为它们仅在列表元素的值上有所不同,这些值是从中抽象出来的。 (甚至没有接近正式证据:()
z
的所需内容为null2 :: [[a]] -> Bool
,其行为会有所不同,因此null1
和null2
同名将需要重载。 (参见FUZxxl的回答)