如何生成从最短到最长的所有可能字符串的列表

2024-03-24

我需要使用数字和字母生成无限的字符串列表。第一个字符串应该只是“a”,然后是“b”到“z”,然后是“0”到“9”,然后是“aa”、“ab”等。

我可以轻松地用一个字符生成那些,但随后它会变得更加复杂。


因此,假设我们已经有了所有可能字符串的列表:

 allStrings :: [String]
 allStrings = ...

Given allStrings,我们如何创建另一个所有可能字符串的列表?

 alsoAllStrings :: [String]

让我们将每个可能的字符串视为单个字符前缀和字符串后缀

 alsoAllStrings = [ c : s 

字符串后缀可以是空字符串,也可以是所有可能字符串列表的成员。

                  | s <- "" : allStrings

单字符前缀位于'a' thru 'z' or '0' thru '9'.

                  , c <- ['a'..'z'] ++ ['0'..'9']
                  ]

(这是使用列表理解 - 我们也可以使用同样的方法concatMap:

alsoAllStrings = concatMap (\s -> map (:s) $ ['a'..'z'] ++ ['0'..'9']) $ "" : allStrings

)

现在让我们回到最初的问题。我们如何找到allStrings?

在大多数语言中,我们不能 - 这是一个无限的字符串列表,程序永远不会完成。但由于 Haskell 很懒,所以只生成尽可能多的内容就很酷了allStrings正如我们实际使用的那样。

这让我们做的一件令人惊讶的事情是我们可以定义allStrings按照alsoAllStrings.

 allStrings = alsoAllStrings

或者,更有可能的是,就其本身而言。

 allStrings = [ c : s | s <- "" : allStrings, c <- ['a'..'z'] ++ ['0'..'9'] ]

这称为核心递归数据 - 根据其自身定义的数据。 在 ghci 中尝试一下:

 ghci> let allStrings = [ c : s | s <- "": allStrings, c <- ['a'..'z'] ++ ['0'..'9'] ]
 ghci> take 100 allStrings
 ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9","aa","ba","ca","da","ea","fa","ga","ha","ia","ja","ka","la","ma","na","oa","pa","qa","ra","sa","ta","ua","va","wa","xa","ya","za","0a","1a","2a","3a","4a","5a","6a","7a","8a","9a","ab","bb","cb","db","eb","fb","gb","hb","ib","jb","kb","lb","mb","nb","ob","pb","qb","rb","sb","tb","ub","vb","wb","xb","yb","zb","0b","1b"]

它起作用的原因(并且不仅仅是无限循环)是它在使用自身之前定义了自身的一部分。我们包含的第一个元素allStrings是空字符串的单字符扩展""。所以当我们开始迭代元素时allStrings用作后缀,前几个元素allStrings已经定义并且可用。我们处理的后缀越多,元素就越多allStrings已定义并可用作后缀。

它与以核心递归方式定义斐波那契数的常见 Haskellism 非常相似:

 fibs = 1 : 1 : zipWith (+) fibs (tail fibs)

如果 corecursion 需要一段时间才能让您理解,请不要感到惊讶。不过,理解这一点还是值得的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何生成从最短到最长的所有可能字符串的列表 的相关文章

随机推荐