从无限列表中获取所有长度为 4 的子串

Getting all Substrings with length 4 out of infinite list

我是 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] 

没有终止。

感谢您的帮助!

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

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

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

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

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

但是我们可以做得更好,例如在这里使用 replicateM :: Monad m => Int -> m a -> 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 字符在我们生成下一个字符串时首先改变。我把它留作练习以获得相反的结果。

这个

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

成功了。

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

与其试图将其全部塞进一个定义,分离您的关注点!首先为更普遍的问题构建解决方案(这是你的 allStrings 定义),然后 使用 它来解决更受限制的问题。这通常会简单得多,尤其是 Haskell.

的惰性评估

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