我尝试使用给定的谓词从列表中删除块。我宁愿使用双字符,例如~/
,但已决定只使用$
。我本来想做的就是这个......
A: "Hello, my $name is$ Danny and I $like$ Haskell"
我想把它变成这样:
B: "Hello, my Danny and I Haskell"
所以我想删除给定符号$
之间的所有内容,或者我的第一个偏好是~/
,如果我能弄明白的话。我试过的是:
s1 :: String -> String
s1 xs = takeWhile (/= '$') xs
s2 :: String -> String
s2 xs = dropWhile (/= '$') xs
s3 :: String -> String
s3 xs = s3 $ s2 $ s1 xs
这个解决方案似乎只是让我的IDE出错(可能是无限循环)。
解决方案:
s3 :: String -> String
s3 xs
|'$' `notElem` xs = xs
|otherwise = takeWhile (/= '$') xs ++ (s3 $ s1 xs)
s1 :: String -> String
s1 xs = drop 1 $ dropWhile (/= '$') $ tail $ snd $ break ('$'==) xs
答案 0 :(得分:4)
这似乎是一个很好的解析器应用程序。使用trifecta的解决方案:
import Control.Applicative
import Data.Foldable
import Data.Functor
import Text.Trifecta
input :: String
input = "Hello, my $name is$ Danny and I $like$ Haskell"
cutChunk :: CharParsing f => f String
cutChunk = "" <$ (char '$' *> many (notChar '$') <* char '$')
cutChunk
匹配$
,后跟0个或更多(many
)个非$
字符,然后是另一个$
。然后我们使用("" <$)
使此解析器的值始终为空字符串,从而丢弃此解析器匹配的所有字符。
includeChunk :: CharParsing f => f String
includeChunk = some (notChar '$')
includeChunk
匹配我们要包含在结果中的文本,即不是$
字符的任何内容。我们使用some
(匹配一个或多个字符)而不是many
(匹配零个或多个字符)非常重要,因为我们将在下一个many
表达式中包含此解析器;如果这个解析器在空字符串上匹配,那么它可以无限循环。
chunks :: CharParsing f => f String
chunks = fold <$> many (cutChunk <|> includeChunk)
chunks
是一切的解析器。将<|>
视为“或”,如“解析cutChunk
或includeChunk
”。 many (cutChunk <|> includeChunk)
是一个解析器,它生成一个块列表,例如Success ["Hello, my ",""," Danny and I ",""," Haskell"]
,所以我们fold
输出将这些块连接成一个字符串。
result :: Result String
result = parseString chunks mempty input
结果:
Success "Hello, my Danny and I Haskell"
答案 1 :(得分:2)
你的无限循环来自于递归调用s3
而没有基本情况:
s3 :: String -> String
s3 xs = s3 $ s2 $ s1 xs
添加基本案例可纠正无限循环:
s3 xs
| '$' `notElem` xs = xs
| otherwise = ...
这不是完整的答案。想一想s1
实际做了什么,以及在哪里使用它的返回值:
s1 "hello $my name is$ ThreeFx" == "hello "
有关详细信息,请参阅break
功能:
break :: (a -> Bool) -> [a] -> ([a], [a])
答案 2 :(得分:2)
我认为你的逻辑是错误的,或许更容易以基本方式编写
Prelude> let pr xs = go xs True
Prelude| where go [] _ = []
Prelude| go (x:xs) f | x=='$' = go xs (not f)
Prelude| | f = x : go xs f
Prelude| | otherwise = go xs f
Prelude|
Prelude> pr "Hello, my $name is$ Danny and I $like$ Haskell"
"Hello, my Danny and I Haskell"
解释标志f
跟踪状态(是否通过模式)。如果当前char是令牌跳过和切换状态。