-2
如果我的輸入是"A1CB1"
如何使輸出變成[A1, C, B1]
?如果我的輸入是「A1CB1」如何使輸出變成[A1,C,B1]?
data Quest = A1 | B1 | C
getQuest :: String -> Maybe [Quest]
如果我的輸入是"A1CB1"
如何使輸出變成[A1, C, B1]
?如果我的輸入是「A1CB1」如何使輸出變成[A1,C,B1]?
data Quest = A1 | B1 | C
getQuest :: String -> Maybe [Quest]
是否有這樣的幫助?大概可以做短/更優雅,但下面的代碼片段,使思想清楚,我希望:
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
嘗試在B12
之前解析B1
,但這並不總是奏效。例如,當有歧義:
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.
順便說一句:對於給定的數據和實例串輸出是不可能的 - 沒有'B1: :Quest' – Carsten
對不起,A2應該是B1 –