从Haskell字符串中删除特定的块

时间:2016-11-06 18:15:19

标签: haskell

我尝试使用给定的谓词从列表中删除块。我宁愿使用双字符,例如~/,但已决定只使用$。我本来想做的就是这个......

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

3 个答案:

答案 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是一切的解析器。将<|>视为“或”,如“解析cutChunkincludeChunk”。 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是令牌跳过和切换状态。