如果我的输入为“A1CB1”,如何使输出变为[A1,C,B1]?

时间:2016-04-20 04:37:59

标签: haskell

如果我的输入为"A1CB1",如何使输出变为[A1, C, B1]

data Quest = A1 | B1 | C
getQuest :: String -> Maybe [Quest]

1 个答案:

答案 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.