这个函数的递归定义

时间:2014-09-29 09:23:16

标签: haskell recursion

我在Haskell中编写了这个使用列表理解的函数。

search :: String -> Char -> [Int]
search str letter = [ num | (x, num) <- (zip str [0..]), letter == x]

如何使用递归定义同一个函数,而不使用像zip这样的库函数?我被允许使用辅助功能。

2 个答案:

答案 0 :(得分:2)

这是一些建议。

在这种递归方案之后,可以找到一种非常有效但有效的解决方案。

search :: String -> Char -> [Int]
search []     letter = ???
search (x:xs) letter = doSomethingWith (search xs letter)
     where doSomethingWith :: [Int] -> [Int]
           doSomethingWith ns = ???

考虑如何将递归调用的结果转换为实际结果。例如:

search "abcb" 'b' = doSomethingWith (search "bcb" 'b') 
                  = doSomethingWith [0,2]
                  should be
                  [1,3]

search "bbcb" 'b' = doSomethingWith (search "bcb" 'b') 
                  = doSomethingWith [0,2]
                  should be
                  [0,1,3]

请注意,在doSomethingWith中,您可以参考x并检查它是否等于letter


为了获得更好的解决方案,请尝试添加一个额外的参数,以便传递当前位置的索引。例如:

search :: String -> Char -> [Int]
search str letter = searchWorker str letter 0  -- initial position is 0

searchWorker :: String -> Char -> Int -> [Int]
searchWorker []     letter position = ???
searchWorker (x:xs) letter position = 
     -- increment position at every recursive call
     doSomethingWith (searchWorker xs letter (position+1))  
     where doSomethingWith :: [Int] -> [Int]
           doSomethingWith ns = ???

这简化了doSomethingWith的编码,因为现在可以假设递归调用产生正确的索引。

searchWorker "abcb" 'b' 0 
                  = doSomethingWith (searchWorker "bcb" 'b' 1) 
                  = doSomethingWith [1,3]
                  should be
                  [1,3]

searchWorker "bbcb" 'b' 0 
                  = doSomethingWith (searchWorker "bcb" 'b' 1) 
                  = doSomethingWith [1,3]
                  should be
                  [0,1,3]

答案 1 :(得分:2)

你有

search :: String -> Char -> [Int]
search str letter = [ num | (x, num) <- (zip str [0..]), letter == x]

它的作用是沿着输入的字符列表(字符串),同时为每个新字符增加索引值1。在执行此操作时,它会测试该字符是否与指定的相同,如果是,则生成它(或者更确切地说是它的索引)。

因此,我们最好通过保护递归对此进行建模,这使我们能够在找到它们时立即生成每个找到的字符(或其索引)。

search str letter = go str <initial-index-value>
   where

这里我们是我们领域的主人,我们可以为我们想要的内部函数提供许多参数 - 我们不限于由列表推导的<-运算符指示的压缩对。此外,我们可以自己计算,根据需要创建新的指数。

     go [] _ = -- we've reached the end of the input.
               -- we should finish up our output
               ....   -- ok, it's the end of any list - an empty list
     go (x:xs) i 
        | x == letter = 

我们可以访问letter,因为go是我们search的内部函数,因此我们可以对它们进行比较。在这里,我们想立即生成这个索引

                         i :  <a recursive call with updated parameters>
        | otherwise  =

这里没什么可生的,只需要制作

                              <a recursive call to continue the search
                                on input list's tail, with the new
                                 current index value>

我们已经完成了。