将字符串转换为自定义数据类型Haskell

时间:2017-10-16 06:08:04

标签: parsing haskell custom-type

我已经创建了一个自定义数据类型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”形式“:+:Var”b“ “这是Expr接受的,但这是我不知道要做的事情,以便更进一步。我的问题是我不知道如何在没有解析器库的情况下从这样的字符串创建Expr。

1 个答案:

答案 0 :(得分: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以及余数字符串。但是可能有很多解析选择,这就是它返回结果列表和剩余部分的原因。

对于使用此类型,我们需要更多实用程序。我离开_给你实施。

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