2016-04-20 5 views

答えて

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を追加)。このケースを説明する1つの方法は、結果をから順番に並べて、parseQuestsがの前に解析して、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. 
関連する問題