Вы можете улучшить монаду Parser
с помощью трансформатора монады StateT
, чтобы получить то, что вы хотите. Это хорошо сочетается с остальной библиотекой, так как большинство комбинаторов используют классы типов, а не конкретные типы (это означает, что вам не нужно много делать для работы кода). Вот достойный пример этого. Он анализирует грамматику с идентификаторами и символами, разделенными пробелами. Каждому идентификатору присваивается уникальный номер.
module Main where
import Text.Trifecta
import Control.Monad.State
import Control.Applicative
import Data.Monoid
data Identifier = Identifier String Int deriving (Show)
identifier :: StateT Int Parser Identifier
identifier = do
name <- some letter
newId <- get
modify (+1)
return $ Identifier name newId
symbolToken :: Parser Char
symbolToken = oneOf "+-*/"
data Token = IdentifierToken Identifier | SymbolToken Char deriving (Show)
singleToken :: StateT Int Parser Token
singleToken = try (IdentifierToken <$> identifier) <|> (SymbolToken <$> lift symbolToken)
parseTokens :: StateT Int Parser [Token]
parseTokens = singleToken `sepBy1` spaces
testParse :: String -> Result [Token]
testParse = parseString (evalStateT parseTokens 0) mempty
test1 :: Result [Token]
test1 = testParse "these are identifiers and + some/symbols -"
test1
приводит:
Success [IdentifierToken (Identifier "these" 0)
,IdentifierToken (Identifier "are" 1)
,IdentifierToken (Identifier "identifiers" 2)
,IdentifierToken (Identifier "and" 3)
,SymbolToken '+',IdentifierToken (Identifier "some" 4)
,SymbolToken '/',IdentifierToken (Identifier "symbols" 5),SymbolToken '-']
Я только что обнаружил ответ неверен. Посмотрите, вы оцениваете состояние перед синтаксическим разбором, что неверно - в таких случаях использования, как если бы вы использовали это состояние для генерации уникальных идентификаторов. –
Вы уверены, что это неправильно? Государство оценивается не только с самого начала, но и через всю программу. 'EvalStateT parseTokens 0' фактически просто устанавливает начальное значение состояния. Так я всегда это делал, и у него, похоже, нет никаких проблем. Если у вас есть пример того, как это дает неожиданный результат, я бы хотел его увидеть! –
Правильно, я был неправ. Этот пример верен - наш пример имел опечатку в очень забавном месте, и мы искали ошибку в совершенно неправильном месте. Я удалю комментарии tommorow, потому что они устарели сейчас. Спасибо! :) –