我似乎经常遇到将关键字直接映射到数据类型的情况,我如下解决了它。它很快就会失控,因为您必须重复字符串值。

有没有更紧凑的方式来表达这一点?

import Text.ParserCombinators.Parsec

data Keyword = Apple | Banana | Cantaloupe

parseKeyword :: Parser Keyword
parseKeyword = (  string "apple"
              <|> string "banana"
              <|> string "cantaloupe"
               ) >>= return . strToKeyword
                    where strToKeyword str = case str of
                           "apple"      -> Apple
                           "banana"     -> Banana
                           "cantaloupe" -> Cantaloupe

编辑:

作为后续问题,因为这似乎太容易了。紧凑的解决方案如何与 try 一起使用?

例如。
import Text.ParserCombinators.Parsec

data Keyword = Apple | Apricot | Banana | Cantaloupe

parseKeyword :: Parser Keyword
parseKeyword = (  try (string "apple")
              <|> string "apricot"
              <|> string "banana"
              <|> string "cantaloupe"
               ) >>= return . strToKeyword
                    where strToKeyword str = case str of
                           "apple"      -> Apple
                           "apricot"    -> Apricot
                           "banana"     -> Banana
                           "cantaloupe" -> Cantaloupe

最佳答案

我不确定这是一个非常优雅的解决方案,但是如果您派生更多类型类:

data Keyword = Apple | Banana | Cantaloupe deriving (Eq, Read, Show, Enum, Bounded)

您可以突然获得所有值:
ghci> [minBound..maxBound] :: [Keyword]
[Apple,Banana,Cantaloupe]

对于任何特定的值,我们可以解析它然后返回值:
parseEnumValue :: (Show a) => a -> Parser a
parseEnumValue val = string (map toLower $ show val) >> return val

然后我们可以结合这些来解析它的任何值:
parseEnum :: (Show a, Enum a, Bounded a) => Parser a
parseEnum = choice $ map parseEnumValue [minBound..maxBound]

试试看:
ghci> parseTest (parseEnum :: Parser Keyword) "cantaloupe"
Cantaloupe
ghci> parseTest (parseEnum :: Parser Keyword) "orange"
parse error at (line 1, column 1):
unexpected "o"
expecting "apple", "banana" or "cantaloupe"

关于haskell - 使用 Parsec 将字符串映射到数据类型的紧凑方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25215184/

10-14 04:20