在Haskell中实现indexOf



我正在学习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的内容和原因)。

最新更新