【问题标题】:Recursive definition of this function该函数的递归定义
【发布时间】:2018-04-10 01:24:19
【问题描述】:

我有这个用 Haskell 编写的函数,它使用列表理解。

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

如何使用递归而不使用像zip 这样的库函数来定义相同的函数?我可以使用辅助功能。

【问题讨论】:

  • 这是作业吗?如果仍然允许,但最好提及它,这样答案会更侧重于教学方面,而不是直接答案部分。
  • 这是我作业的一部分。上面引用的代码是我写的

标签: haskell recursion


【解决方案1】:

这里有一些建议。

遵循此递归方案可以找到一种效率低但可行的解决方案。

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]

【讨论】:

    【解决方案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
    

    在这里,我们是我们领域的主人,我们可以为我们想要的内部函数设置许多参数——我们不限于由列表理解的&lt;- 运算符指定的压缩对。此外,我们可以自己计算,根据需要创建新的索引。

         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>
    

    我们已经完成了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 2014-07-11
      • 1970-01-01
      • 2023-01-12
      • 2017-07-10
      • 2012-09-26
      相关资源
      最近更新 更多