我正在尝试编写一个函数来使用尾递归来查找给定元素的索引。可以说列表中包含1
到10
的数字,我正在搜索5
,然后输出应为4
。我遇到的问题是使用尾递归'计数'。但是,在这种情况下,我甚至不确定是否需要对递归调用的数量进行“计数”。我尝试使用!!
没有帮助,因为它返回特定位置的元素。我需要函数来返回特定元素的位置(正好相反)。
我一直想把这个拿出一个小时了。
代码:
whatIndex a [] = error "cannot search empty list"
whatIndex a (x:xs) = foo a as
where
foo m [] = error "empty list"
foo m (y:ys) = if m==y then --get index of y
else foo m ys
注意:我试图在不使用库函数的情况下实现它
答案 0 :(得分:4)
您的辅助函数需要一个额外的计数参数。
whatIndex a as = foo as 0
where
foo [] _ = error "empty list"
foo (y:ys) c
| a == y = c
| otherwise = foo ys (c+1)
顺便说一下,给这个函数一个Maybe
返回类型而不是使用错误的形式更好。这也是elemIndex
的工作原理,这是有充分理由的。这看起来像
whatIndex a as = foo as 0
where
foo [] _ = Nothing
foo (y:ys) c
| a == y = Just c
| otherwise = foo ys (c+1)
答案 1 :(得分:3)
注意:我试图在不使用库函数的情况下实现它
这一般不是一个好主意。这是一个更好的练习:
通过这种方式,您将学习三项关键技能:
但是,在这种情况下,您的whatIndex
或多或少与elemIndex
in Data.List
的功能相同,因此您的问题会减少到编写自己的此库函数版本。
这里的诀窍是你想要在递减列表时增加一个计数器。有一种编写尾递归函数的标准技术,称为累积参数。它的工作原理如下:
因此对于elemIndex
,辅助函数将是这样的(使用i
作为当前元素索引的累积参数):
-- I'll leave the blanks for you to fill.
elemIndex' i x [] = ...
elemIndex' i x (x':xs) = ...
然后“驱动程序”功能是这样的:
elemIndex x xs = elemIndex 0 x xs
但是这里有一个严重的问题我必须提到:让这个函数在Haskell中表现良好是很棘手的。尾递归是严格(非惰性)函数式语言中的一个有用技巧,但在Haskell中并不是很多,因为:
This older answer of mine显示了第二点的示例。
因此,在您的情况下,非尾递归解决方案可能是您可以在恒定空间中运行的最简单的解决方案(即,不会将堆栈放在长列表中):
elemIndex x xs = elemIndex' x (zip xs [0..])
elemIndex' x pairs = snd (find (\(x', i) -> x == x') pairs)
-- | Combine two lists by pairing together their first elements, their second
-- elements, etc., until one of the lists runs out.
--
-- EXERCISE: write this function on your own!
zip :: [a] -> [b] -> [(a, b)]
zip xs ys = ...
-- | Return the first element x of xs such that pred x == True. Returns Nothing if
-- there isn't one, Just x if there is one.
--
-- EXERCISE: write this function on your own!
find :: (a -> Bool) -> [a] -> Maybe a
find pred xs = ...