List 测试代码时出现大索引问题
我正在努力学习Haskell,我想写一个递归函数,不使用任何库函数。功能List 测试代码时出现大索引问题,list,haskell,testing,List,Haskell,Testing,我正在努力学习Haskell,我想写一个递归函数,不使用任何库函数。功能 nth ::Integer -> [a ] -> Maybe a 获取索引n和元素列表,并返回列表的第n个元素(如果该索引有效),如果无效,则不返回任何内容 索引无效 我的代码: nth :: Integer -> [a] -> Maybe a nth a [] = Nothing nth a (x:xs) |a == 1 = Just x |fromIntegral
nth ::Integer -> [a ] -> Maybe a
获取索引n和元素列表,并返回列表的第n个元素(如果该索引有效),如果无效,则不返回任何内容
索引无效
我的代码:
nth :: Integer -> [a] -> Maybe a
nth a [] = Nothing
nth a (x:xs) |a == 1 = Just x
|fromIntegral (length xs) < a = Nothing
|a==0 = Nothing
| otherwise = nth (a-1) xs
您的函数存在一些问题。第一种情况(行为类似于
(!!)
)失败的原因是(!!)::Int->[a]->a
使用基于零的索引,而您的函数似乎使用基于一的索引。这意味着您将因此需要减少为函数指定的索引
此外,在函数中,您可以比较n
和from integral(length xs)
。因为<代码> xs<代码>是列表的尾部,所以检查是不正确的,因为在某些情况下,它永远不会考虑最后一个元素。事实上:
Prelude> nth 2 [0, 2]
Nothing
此外,在每次迭代中使用length
通常不是一个好主意<代码>长度以O(n)为单位运行,这意味着您的算法现在以O(n2)为单位运行,因此随着列表的增长,这将很容易开始花费大量时间
解决此问题的一种更简短、更优雅的方法可能是:
nth :: Integral i => i -> [a] -> Maybe a
nth 1 (x:_) = Just x
nth i (_:xs) | i < 1 = Nothing
| otherwise = nth (i-1) xs
nth _ [] = Nothing
因此,第一个值排除n长度xs
,从而检查值是否为Just(xs!!(n-1))
在第二种情况下,排除大于零的值,并检查所有剩余索引是否映射到Nothing
最后,最后一个属性检查对于大于长度xs
的值,我们也没有得到任何结果
请注意,此处
nth
使用基于一的索引。我把它留作一个练习,让它以零为基础。您意识到您的函数定义中的长度xs
比列表的长度少一个,因为您在这里计算尾部的长度,对吗?我不确定为什么只是从a=1
返回x,而不是从a=0
返回?或者这是在尝试实现基于1的索引…:P@TrebledJ这是我的主意是的。这本身不是问题。这肯定会让它更具挑战性。为什么您的ntha(x:xs)
部件有4个不同的条件/分支?应该只有2个。我只需完全删除length
检查。递归情况应该意味着所有访问过大索引的尝试最终都会得到一个空列表的索引,您已经介绍过了。计算每个递归步骤的长度会使这个函数异常缓慢。实际上,我不允许更改规范部分,因为这是问题的一部分。我已经按照您编写代码的方式更改了代码,但是,对于大索引,我也遇到了同样的失败。它实际上应该是有效的,因为如果我在不使用测试的情况下尝试它,那么如果我尝试例如nth 1000[1,2,3],它会给我“什么都没有”@Dania:你意识到,因为这是一个基,测试的边界应该有细微的不同?是的,在我的测试中,他们测试的是零基的。我现在把代码改成这样:nth::Integer->[a]->可能是第n个0(x:))=没有第n个1(x:))=只有x个n个a():xs)| a<0=没有|否则=第n个(a-1)xs个n(u[]=没有
@Dania:但这不足以使它以零为基础。它现在可以工作了| a<0=无|否则=第n(a-1)x第n[]=无
谢谢
nth :: Integral i => i -> [a] -> Maybe a
nth 1 (x:_) = Just x
nth i (_:xs) | i < 1 = Nothing
| otherwise = nth (i-1) xs
nth _ [] = Nothing
describe "nth" $ do
it "for valid indexes it behaves like (!!)" $
property $ \n xs -> n <= 0 || n > length (xs :: [Integer]) || Lists.nth n xs == Just (xs !! (n-1))
it "for negative indexes it returns Nothing" $
property $ \n xs -> n > 0 || Lists.nth n (xs :: [Integer]) == Nothing
it "for too large indexes it returns Nothing" $
property $ \n xs -> n <= length xs || Lists.nth n (xs :: [Integer]) == Nothing