递归findIndices

时间:2011-12-10 13:21:27

标签: haskell recursion

我的任务是编写一个与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'”。而我似乎无法弄清楚问题。

感谢您的回答。

4 个答案:

答案 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是否通过测试。这是错的。尝试使用ifcase语句来区分两种不同的情况。此外,如果使用显式递归,则必须明确处理空列表大小写:

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
相关问题