【问题标题】:How to stop recursing and produce the list in memory如何停止递归并在内存中生成列表
【发布时间】:2014-10-23 23:49:25
【问题描述】:

(1.) 函数“sameString”返回一个布尔值,判断两个字符串是否相同,无论大小写。

--  *Main> sameString "HeLLo" "HElLo"
--   True
--   *Main> sameString "Hello" "Hi there"
--   False


sameString :: String -> String -> Bool
sameString str1 str2
    | length str1 == length str2 = and [ a == b | (a,b) <- zip (capitalise str1) (capitalise str2) ]
    | otherwise = False

(1) 辅助函数“capitalise”进行大写。

capitalise :: String -> String
capitalise str = [ toUpper x | x <- str ]

(2) 函数“prefix”返回一个布尔值,表明第一个字符串是否是第二个字符串的前缀,无论大小写。

--  *Main> prefix "bc" "abCDE"
--  False
--  *Main> prefix "Bc" "bCDE"
--  True

prefix :: String -> String -> Bool
prefix [] [] = True
prefix substr str
    | sameString string' substr == True = True
    | otherwise = False
    where chop_str :: String -> String -> String
          chop_str str substr = (take (length substr) str)
          string' = chop_str str substr   

(3.) 函数“dropUntil”返回第一个字符串第一次出现后第二个字符串的内容。如果第二个字符串不包含第一个作为子字符串,它应该返回空字符串。

*Main> dropUntil "cd" "abcdef"
"ef"

 dropUntil :: String -> String -> String
 dropUntil substr [] = ""
 dropUntil substr (s:tr)
    | prefix substr (s:tr) == False = drop 1 s : dropUntil substr tr
    | prefix substr (s:tr) == True =  

所以现在的问题。我正在考虑用递归做 dropUntil 。

我认为上面的函数应该做的是:

1) 给定一个字符串和一个子字符串(子字符串不是字符串的前缀)...

它应该放弃字符串的头部...

并将空列表“”改为

... 对剩余尾部和相同子字符串的递归调用。

其背后的想法是不断删除列表的头部,直到子字符串成为列表的前缀,然后函数应该生成字符串的其余部分作为结果。

但是,我不知道该怎么做。我本质上想要做的是制作

| prefix substr (s:tr) == True =  "leftover_string"

其中“leftover_string”是递归调用丢弃元素后剩余的内容,直到满足子字符串是余数的前缀的条件。

可以按照我开始的方式进行吗?

【问题讨论】:

  • (此评论离题。)请记住,尤其是如果您是学生,“字母”,尤其是在 Unicode 中,比您想象的要复杂。您的函数capitalize = map toUpper,特别是作为不区分大小写比较的代理,被认为是不好的做法。对于实际使用,请考虑使用case conversion functions in Data.Text

标签: haskell recursion


【解决方案1】:

在过去的几天里,我们遇到了很多问题,其中涉及运行一个平等的[x] 和其他一些[x] 寻找isPrefixOf。从那时起在我的思维过程中出现的一个原语在这里非常有价值:

import Data.List

splitAtSublist :: ([x] -> Bool) -> [x] -> Maybe ([x], [x])
splitAtSublist pred list = find (pred . snd) $ zip (inits list) (tails list)

字符串"abcd" 的拆分zip (inits list) (tails list) 看起来像[("", "abcd"), ("a", "bcd"), ("ab", "cd"), ("abc", "d"), ("abcd", ""))]。这会找到拆分的“尾端”满足谓词pred 的第一个元素。

要从这个基础上得到dropUntil s,我们可以这样做:

dropUntil p ls = 
    maybe "" (drop (length p) . snd) $ 
        splitAtSublist (p `isPrefixOf`) ls

isPrefixOf 也来自Data.List。代入,我们发现我们根本不使用inits list,它只是变成:

dropUntil p = maybe "" (drop $ length p) . find (p `isPrefixOf`) . tails

这很简单。

【讨论】:

  • User5402 提供了我正在寻找的确切答案,但这也很棒。我是 Haskell 的初学者,所以我必须查找一些函数,但我有点了解它的要点。希望我能抽出时间详细研究您的答案,我非常感激,克里斯!
【解决方案2】:

这是你想要的吗?

| prefix substr (s:tr) == True =  drop (length substr) (s:tr)

一些注意事项:

这里有一个类型错误:

| prefix substr (s:tr) == False = drop 1 s : dropUntil substr tr
                                  ^^^^^^^^

我想你只是想要:

| prefix substr (s:tr) == False = dropUntil substr tr

【讨论】:

  • 感谢您指出可怕的类型错误。是的,这正是我的意思,而且非常有意义!谢谢!
猜你喜欢
  • 2021-12-24
  • 2014-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-18
  • 2021-07-20
相关资源
最近更新 更多