编辑:事实证明,通过折叠模式而不是字符串,代码变得更简单、更短,类似于
"" `isPrefixOf` undefined
作品。谢谢@dfeuer 和@WillNess。这是更新的程序:
isPrefixOf pattern s = foldr g (const True) pattern s
where
g x r (h:t)
| x == h = r t
| otherwise = False
它的工作方式与以下程序几乎相同,因此请参阅该程序的说明。
我设法只使用foldr 来解决它:
isPrefixOf :: String -> String -> Bool
p `isPrefixOf` s = isPrefixOfS p
where
isPrefixOfS
= foldr
(\c acc ->
\str -> case str of
x:xs -> if c == x
then acc xs
else False
[] -> True
)
null
s
这是解释。
为了创建函数isPrefixOf,我们需要这样:
isPrefixOf pattern s
= case pattern of
[] -> True
x:xs -> if (null s) then False
else if (head s) /= x
then False
else xs `isPrefixOf` (tail s)
好吧,让我们简化一下——让我们创建一个名为isPrefixOfS 的函数,它只接受一个模式,它会自动与s 进行比较。我们需要构建这个嵌套函数链:
-- Pseudocode, not actual Haskell
\p -> case p of
[] -> True
x:xs -> if x /= (s !! 0)
then False
else <apply xs to> \q -> case q of [] -> True
x:xs -> if x /= (s !! 1) -- Note that we've incremented the index
then False
else <apply xs to> \r -> ....
这似乎很容易解释 - 如果需要进一步解释,请在评论中告诉我。
好吧,我们可以看到这个链有一个递归属性,s 的最后一个字符将在嵌套最深的 lambda 中进行比较。所以我们需要从右到左嵌套 lambdas。我们可以为此使用什么? foldr。
isPrefixOfS
= foldr -- Folding from right to left across `s`
(\c acc -> -- `c` is the current character of `s`, acc is the chain of nested functions so far
\str -> -- We return a function in the fold that takes a String
case str of
-- If the string is not null:
x:xs -> if c == x -- If the head of the string is equal to the current character of s,
then acc xs -- Then pass the tail of the string to the nested function which will compare it with subsequent characters of s
else False -- Otherwise we return false
-- If the string is null, we have completely matched the prefix and so return True
[] -> True
)
null -- Innermost nested function - we need to make sure that if the prefix reaches here, it is null, i.e. we have entirely matched it
s
现在我们在p 上使用这个函数isPrefixOfS:
p `isPrefixOf` s = isPrefixOfS p
编辑: 我刚刚找到this post,它使用类似的逻辑来实现zip,就foldr而言,你可能也想看看。