我的任务是编写一个与findIndices基本相同但以递归方式运行的函数。到目前为止,我已设法做到这一点:
getIndicesFor :: (a -> Bool) -> [a] -> [Int]
getIndicesFor x (y:ys) = (fst (head(filter ((x y).snd) as ))):getIndicesFor x ys where
as = (zip [0..] (y:ys))
但这导致错误说:“无法匹配预期类型b0 -> Bool' with actual type
Bool'”。而我似乎无法弄清楚问题。
感谢您的回答。
答案 0 :(得分:3)
我想我可以看到类型错误。您使用表达式
((x y).snd)
作为过滤函数,应该具有类型(Int, a) -> Bool
。但是,你有
x :: a -> Bool
y :: a
使得(x y) :: Bool
。但是你试图将这个东西后期组合到snd
来构建一个过滤函数,只有当它是something -> Bool
类型的函数时才会起作用。这就是错误信息所呻吟的。
在问题的上下文中,当y
只是列表中的一个元素时,我不清楚为什么要使用y
来构建过滤函数重新调查。我也不清楚为什么你需要在任何情况下将列表分解为(y:ys)
。
你的尝试有很多正确的逻辑,但'管道'需要工作。在整理过滤功能后,您需要查看处理filter
输出的方式,以获得所需的数据。
现在,如果我正在编写这个程序,我会认真考虑使用list comprehensions:如果你还没有看过它们,那就值得一试。
答案 1 :(得分:2)
一些注释。
如果您需要编写与elemIndices
相同的功能,则getIndicesFor
应具有相同的签名:: Eq a => a -> [a] -> [Int]
关注filter ((x y).snd)
。好像你想要过滤对,其中第二个元素等于x
。为了弄清楚第二个元组元素等于x,我们可以使用像(\tuple -> snd tuple == x)
这样的lambda函数
(y:ys)
使用了两次,因此您可以使用list@(y:ys)
,然后将其称为list
,而不是(y:ys)
。
最好使用$
代替方括号。
当你定义递归函数时,你不应该忘记匹配空列表情况。
使用head
功能时要小心。这是不安全的,因为如果list-argument为空,它可以返回错误异常。 [*** Exception: Prelude.head: empty list
在当前状态下,您的函数返回元素(因为使用fst
),而不是索引。您应该注意事实,x
中(y:ys)
元素的索引可能与原始列表中该元素的索引不同。
答案 2 :(得分:1)
可以使用do notation编写此函数。我不会觉得这很糟糕,因为你可能不会因提交作为答案而获得赞誉,因为它不使用显式递归:
import Control.Monad (guard)
getIndicesFor :: (a -> Bool) -> [a] -> [Int]
getIndicesFor f xs = do
(n, x) <- zip [0..] xs
guard (f x)
return n
-- in fact you could write it compactly as a list comprehension
-- though I personally avoid list comprehensions, as I find "do" syntax clearer
-- getIndicesFor f xs = [n | (n, x) <- zip [0..] xs, f x]
...测试
ghci> take 5 $ getIndicesFor even [0 ..]
[0, 2, 4, 6, 8]
ghci> take 5 $ getIndicesFor even [2, 4 ..]
[0,1,2,3,4]
所以这个概念很简单,对吧?从列表中选择一个元素,使用指定的函数对其进行测试,如果它通过则将其索引添加到列表中。
如果必须使用显式递归编写此函数,则需要以不同方式处理这两种情况:此特定元素是否通过测试?如果它通过,则将其索引添加到结果列表中。如果失败,那么就不会。这是我现在在代码中看到的主要问题。
getIndicesFor x (y:ys) = blahblah : getIndicesFor x ys
总是添加某些内容,无论y
是否通过测试。这是错的。尝试使用if
或case
语句来区分两种不同的情况。此外,如果使用显式递归,则必须明确处理空列表大小写:
getIndicesFor x [] = ???
答案 3 :(得分:-2)
getIndicesFor :: (a -> Bool) -> [a] -> [Int]
getIndicesFor f xs = map fst (filter (f.snd) as)
where
as = zip [0..] xs
如果使用as =(zip [0 ..] xs)那么你无法递归定义getIndicesFor direct
使用辅助函数重写
getIndicesFor :: (a -> Bool) -> [a] -> [Int]
getIndicesFor f xs = aux as
where
as = zip [0..] xs
aux [] = []
aux (x:xs) =
if (f.snd) x then
(fst x) : aux xs
else
aux xs