【问题标题】:Convert string to custom data type Haskell [closed]将字符串转换为自定义数据类型 Haskell [关闭]
【发布时间】:2017-10-16 06:08:03
【问题描述】:

我创建了一个自定义数据类型 Expr

type Name = String
type Domain = [Integer]
data Expr = Val Integer
 | Var Name
 | Expr :+: Expr
 | Expr :-: Expr
 | Expr :*: Expr
 | Expr :/: Expr
 | Expr :%: Expr
    deriving Eq

我需要创建一个解析器,它可以在不使用 Haskell 中的解析器库的情况下从字符串创建数据类型 Expr。

我已经为初始字符串创建了解析器,它接受形式为“2*a+b”的字符串并将其转换为形式“Val 2 :*: Var "a" :+: Var "b" " 这被 Expr 接受,但这是我不知道为了更进一步而要做的事情。我的问题是我不知道如何在没有解析器库的情况下从这样的字符串创建 Expr。

【问题讨论】:

  • 为什么不想使用解析器库?
  • 因为我不允许使用它。
  • 这个家庭作业有什么限制?
  • 此时您在问“如何编写解析器”,这对于 SO 问题来说可能过于宽泛。
  • 你的课程肯定教会了你一些东西,可以大致指明前进的方向吗?否则,这个问题就太宽泛了。

标签: parsing haskell custom-type


【解决方案1】:
import Control.Applicative (Alternative (empty, many, some, (<|>)), (<**>))
import Data.Char           (isSpace, isDigit)
import Data.Maybe          (listToMaybe)

编写一个基本的、低效的解析库实际上并不难,只需不到 50 行代码即可完成。核心类型如下所示:

newtype Parser a = Parser (String -> [(a, String)])

parse :: Parser a -> String -> Maybe a
parse (Parser p) s = listToMaybe $ fst <$> p s

此解析器部分使用字符串并返回解析结果a 以及剩余字符串。但是可能有许多解析替代方案,这就是它返回结果和余数列表的原因。

为了使用这种类型,我们需要更多的实用程序。我留下了_s 供您实施。

instance Functor Parser where
   fmap (Parser p) = _

instance Applicative Parser where
   pure a = Parser $ \s -> (a, s) -- Consumes nothing and returns a
   Parser pf <*> Parser pa = _    -- Parse pf, then parse pa and apply the result
                                  -- of pf to that of pa.

instance Alternative Parser where
   empty = Parser $ \s -> []   -- Matches nothing
   Parser p1 <|> Parser p2 = _ -- Matches either p1 or if that fails p2.

satisfy :: (Char -> Bool) -> Parser Char
satisfy = _

space :: Parser ()
space = () <$ satisfy isSpace

spaces :: Parser ()
spaces = () <$ many space

char :: Char -> Parser Char
char c = satisfy (c ==)

-- | Detects the end of file.
eof :: Parser ()
eof = _

-- | Succeeds when at the end of a word, without consuming any input
eow :: Parser ()
eow = _

现在我们可以继续使用这个解析器,就像使用任何递归下降解析器一样:

data Expr = Val Integer
          | Expr :*: Expr
          | Expr :+: Expr
  deriving Show

parseVal :: Parser Expr
parseVal =
  char '(' *> parseAdd <* char ')' <|>
  Val . read <$> some (satisfy isDigit) <* eow

parseMul :: Parser Expr
parseMul = _

parseAdd :: Parser Expr
parseAdd = _

parseExpr :: Parser Expr
parseExpr = parseAdd <* eof

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-12
    • 2021-02-17
    • 2013-11-27
    • 1970-01-01
    • 2019-11-22
    • 2017-06-22
    • 2020-03-17
    相关资源
    最近更新 更多