【问题标题】:Getting all Substrings with length 4 out of infinite list从无限列表中获取所有长度为 4 的子字符串
【发布时间】:2020-02-04 20:31:07
【问题描述】:

我对 Haskell 很陌生,我正在尝试解决以下问题:

我有一个函数,可以生成一个无限长的不同长度的字符串列表。但是一定长度的字符串数量是有限制的。

现在我想提取列表中具有特定长度 n 的所有子字符串。不幸的是,我做了很多研究并尝试了很多东西,但没有一个对我有用。

我知道filter() 不起作用,因为它会检查列表的每个部分并导致无限循环。

这是我生成无限列表的函数:

allStrings =  [ c : s | s <- "" : allStrings, c <- ['R', 'T', 'P']]

我已经试过了:

allStrings = [x | x <- [ c : s | s <- "" : allStrings, 
                  c <- ['R', 'T', 'P']], length x == 4] 

没有终止。

感谢您的帮助!

【问题讨论】:

  • filter 不会导致无限循环,因为它以惰性方式工作。只有当你完全评估列表时,它当然会陷入无限循环。
  • allStrings = [ c : s | s
  • @WillemVanOnsem 不会print . filter (&gt;0) $ [0..]“全面评估列表”?
  • @T.Naz: 那是因为你的allStrings 永远不会发出什么东西,因为你说它应该是长度4,但是为了在这里构造一个长度为4 的列表,你首先需要allStrings 来构造一个长度为3 等的列表
  • @WillNess:是的,因为,如前所述,print 将完全评估该列表,因此一旦您开始 printing,您将永远无法摆脱它。

标签: list haskell functional-programming infinite enumerate


【解决方案1】:

问题是您的过滤器无法生成任何解决方案。为了生成长度为4 的字符串,您首先需要生成长度为3 的字符串,因为您每次都在其前面加上一个 字符。为了生成长度为3 的列表,因此需要生成长度为2 的字符串,依此类推,直到基本情况:一个空字符串。

主要问题不是过滤器本身,问题在于您过滤的方式使得现在不可能发出值。

我们可以通过使用不同的列表来构建字符串来解决这个问题,并过滤该列表:

allStrings = filter ((==) 4 . length) vals
    where vals = [x | x <- [ c : s | s <- "" : vals, c <- "RTP"]]

这将发出所有长度为4 的列表,然后陷入无限循环,因为filter 将继续搜索更多字符串,但找不到这些。

但是我们可以做得更好,例如在这里使用replicateM :: Monad m =&gt; Int -&gt; m a -&gt; m [a]

Prelude Control.Monad> replicateM 4 "RTP"
["RRRR","RRRT","RRRP","RRTR","RRTT","RRTP","RRPR","RRPT","RRPP","RTRR","RTRT","RTRP","RTTR","RTTT","RTTP","RTPR","RTPT","RTPP","RPRR","RPRT","RPRP","RPTR","RPTT","RPTP","RPPR","RPPT","RPPP","TRRR","TRRT","TRRP","TRTR","TRTT","TRTP","TRPR","TRPT","TRPP","TTRR","TTRT","TTRP","TTTR","TTTT","TTTP","TTPR","TTPT","TTPP","TPRR","TPRT","TPRP","TPTR","TPTT","TPTP","TPPR","TPPT","TPPP","PRRR","PRRT","PRRP","PRTR","PRTT","PRTP","PRPR","PRPT","PRPP","PTRR","PTRT","PTRP","PTTR","PTTT","PTTP","PTPR","PTPT","PTPP","PPRR","PPRT","PPRP","PPTR","PPTT","PPTP","PPPR","PPPT","PPPP"]

请注意,这里的 last 字符在我们生成下一个字符串时首先发生变化。我把它作为一个练习来获得相反的结果。

【讨论】:

    【解决方案2】:

    这个

    allStrings4 = takeWhile ((== 4) . length) . 
                    dropWhile ((< 4) . length) $ allStrings
    

    成功了。

    之所以有效,是因为您的(第一个)allStrings 定义以高效 的方式巧妙地生成了包含'R''T''P' 字母的所有字符串,长度递减顺序。

    不要试图把它全部塞进一个定义中,把你的顾虑分开!首先为更普遍的问题建立一个解决方案(这是你的allStrings定义) ,然后使用它来解决更受限制的问题。这通常会简单得多,尤其是使用 Haskell 的惰性求值时。

    我们只需要注意我们的流总是高效的,永远不会卡住

    【讨论】:

    • allStrings 这里指的是你的 first 定义。 从不使用相同的名称来指代不同的事物。总是给它们编号:allStringsallStrings2 等,所以不会混淆。
    • “切勿使用相同的名称来指代不同的事物”是一个难以理解的准则。我们通常使用xs 来指代整个程序过程中的许多不同事物。我不知道你的意思是什么,所以我不能为你提供一个很好的澄清。
    • 我认为更好的指导方针是避免名称阴影,除非您非常确定要这样做。如果您启用-Wall-Wname-shadowing,编译器会警告您。
    • @amalloy 我的意思是“在同一个问题中”,最终。或者更广泛地说,在 GHCi 提示下探索“互动游戏”期间。
    • (我很惊讶它不清楚顺便说一句。显然这句话是在上下文中提出的,我想,OP询问了两个具有相同名称的不同定义,其中令人困惑,等等——都在同一条评论中提到)
    猜你喜欢
    • 1970-01-01
    • 2021-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 2022-11-13
    • 1970-01-01
    相关资源
    最近更新 更多