如果我的输入为"A1CB1"
,如何使输出变为[A1, C, B1]
?
data Quest = A1 | B1 | C
getQuest :: String -> Maybe [Quest]
答案 0 :(得分:1)
这样的事情有帮助吗?它可以更短/更优雅地完成,但下面的片段使我的想法明确,我希望:
import Data.List
import Data.Maybe
data Quest = A1 | B1 | C deriving
( Enum -- Defines sequential ordering
, Bounded -- Name the lower and upper limits of a type
, Show -- String conversion
, Read -- Conversion from string
)
-- A parser for "a" is a function that works on input,
-- and then possibly yields a value of type "a", and the
-- remaining input.
type Parser a = String -> (Maybe a, String)
-- Give us all possible quests.
allQuests :: [Quest]
allQuests = [minBound..]
-- Simply lift a value to the "Parser" domain.
yield :: a -> Parser a
yield value = \input -> (Just value, input)
-- A parser that always fails.
decline :: Parser a
decline = \input -> (Nothing, input)
-- Creates a parser for a given Quest.
-- maybe: http://hackage.haskell.org/package/base-4.8.2.0/docs/Prelude.html#v:maybe
-- stripPrefix: http://hackage.haskell.org/package/base-4.8.2.0/docs/Data-List.html#v:stripPrefix
parseQuest :: Quest -> Parser Quest
parseQuest quest = \input ->
maybe (decline input) -- Default: decline the input
(yield quest) -- If we found the correct prefix: yield it.
(stripPrefix (show quest) input) -- Try to strip the prefix.
-- Parse a string into a list of quests.
-- Defined to be somewhat fault tolerant: the function
-- will attempt to parse as much as it can, and will yield
-- the remaining input in its result.
-- find: http://hackage.haskell.org/package/base-4.8.2.0/docs/Data-List.html#v:find
--
parseQuests :: Parser [Quest]
parseQuests = \input ->
let parsers = map parseQuest allQuests -- A list of parsers; one for each quest.
results = map ($ input) parsers -- Each parser is applied to "input".
in case find (isJust . fst) results of -- Stop when one parser succeeded.
Nothing -> yield [] input -- No quest could be parsed.
Just (Just quest, rest) ->
let (Just quests, rest') = parseQuests rest -- Parse the rest recursively.
in yield (quest:quests) rest' -- And then yield it all.
这给出了:
parseQuests "A1CB1" == (Just [A1,C,B1],"")
或者如果你想要与你的功能相同的东西:
getQuest = fromJust . fst . parseQuests
那样
getQuest "A1CB1" == [A1,C,B1]
注意:我没有考虑重叠的构造函数名称(例如添加B12 :: Quest
)。解决此案例的一种方法是从allQuests
订购结果,以便parseQuests
尝试在B1
之前解析B12
,但这并不总是有效。例如,当存在歧义时:
data Quest = C1 | EC1 | E
-- Should input "EC1" be parsed as [E, C1] or [EC1]?
或者当只有某个组合成功解析时:
data Quest = AB | ABC | DE
-- Input "ABCDE" would only parse as [ABC, DE],
-- but will fail when parsing starts with AB.