我正在学习Learn You a Haskell教程,并试图从递归部分修改elem'
函数。
最初的elem'
功能是:
elem' :: (Eq a) => a -> [a] -> Bool
elem' a [] = False
elem' a (x:xs)
| a == x = True
| otherwise = a `elem'` xs
我的indexOf
功能是:
indexOf :: (Eq a, Integral s) => a -> [a] -> s -> s
indexOf _ [] _ = -1
indexOf a (x:xs) s
| a == x = s
| otherwise = indexOf a xs s+1
函数应该返回列表中元素的索引,如果找不到元素,则返回-1
。
在我的.hs
文件的末尾,我用测试了这个功能
main = putStrLn(show(indexOf 7 [1,2,3] 0))
该函数可正确查找列表中显示的值。但是,对于上面编写的测试,它没有返回-1
,而是打印2
。返回值似乎总是列表长度减去1。
在遇到边缘条件(空列表)后,我希望-1
返回值通过调用堆栈一直向上传播。我的错在哪里?
您遇到了一个优先级问题。函数应用程序比(+)
绑定得更紧密,因此otherwise
的情况被解析为(index' a xs s) + 1
。
您可以对上面的示例进行一个简单的更改,这几乎可以保证修复您的错误。将返回类型更改为Maybe a
,失败时返回Nothing
。虽然单凭这一点并不能修复你的错误,但它给编译器提供了足够的信息,它将引导你走上正确的道路,你将能够自己修复它。
在失败时返回-1
是一件非常"c"的事情,而且很容易出错。在您的情况下,编译器将-1
与实际的数组索引混淆,当您返回递归调用时,可以将其添加到。(我可以从签名中看出这不是你的意图,但编译器就是这样解释你所做的)。
(一个额外的优势-一旦你掌握了使用正确类型的艺术,你很快就会意识到使用类型为a->Maybe b
或更广泛地说是a->m b
的函数是多么困难,其中m
是某种包装类型……这将使你了解我们使用monad的内容和原因)。