Во-первых, о "???"
, который вам пришлось оставить там.Рассмотрим ваше определение Pstate
:
data Pstate a = Pstate (String -> ([PToken String], PStream)) a
Это означает, что ваш конструктор данных имеет следующий тип:
Pstate :: (String -> ([PToken String], PStream)) -> a -> Pstate a
Это конструкция по умолчанию для монады.Если вы определяете монадные комбинаторы, то на самом деле нередко бывает, что некоторые комбинаторы там, где это не нужно, поэтому в данном случае принято оставить значение ()
.
Но на самом деле я думаю, что ваш код оченьстранно, кажется, что вы не поняли смысл монады с состоянием.Позвольте мне объяснить:
Обычно вычисление с состоянием имеет такой тип:
data MyState a = MyState (TypeOfState -> (a, TypeOfState))
Это означает, что ваше монадическое действие на самом деле является своего рода вычислением, которое делает что-то (возможно с вашей частьюсостояния), а затем возвращает результат и новое состояние.Состояние заключено в монаде, поэтому вам не нужно об этом думать.
В вашем коде вы используете тот же шаблон, но несколько другой.Похоже, что вы исправили результат вычисления на [PToken String]
.Позвольте мне немного исправить ваше определение:
data Pstate a = Pstate (PStream -> (a, PStream))
Итак, теперь вы получаете возвращаемое значение вашего вычисления, применяя комбинаторы, которые выглядят так:
instance Monad Pstate where
-- return should just wrap the computation up, so no changes
return x = Pstate (\p -> (x,p))
parser1 >>= parser2 = Pstate $ \input -> let
Pstate parser1' = parser1
Pstate parser2' = parser2
(output, rest) = parser1' input
result = parser2' output rest
in result
Теперь,вы можете посмотреть на сигнатуры типов для ваших парсеров, они должны выглядеть примерно так: parseFid :: Pstate [PToken PStream]
.Это означает, что ваш синтаксический анализатор потребляет некоторый ввод и возвращает проанализированный материал как [PToken PStream]
и устанавливает новый вход в то, что осталось.Рассмотрим определение parseFid
о том, как оно может выглядеть:
parseFid :: Pstate [PToken PStream]
parseFid = Pstate $ \r -> let (fid, rest) = span (/= '(') r in ([("fid", fid)],rest)
Остальное оставлено в качестве упражнения для читателя.Я бы посоветовал вам переформулировать ваш парсер, используя вместо этого монаду State
из Control.Monad.State.Strict
.Вы увидите, что приведенная выше монада в основном та же самая.
На самом деле, в большинстве случаев проще полагаться на существующие и хорошо известные инструменты вместо того, чтобы сворачивать собственный анализатор.Вот синтаксический анализатор того, что вам нужно создать с помощью Parsec
, современной библиотеки для анализа:
import Text.Parsec
parseFunction = do name <- parseName
obrace <- parseOpeningBrace
args <- parseArguments
cbrace <- parseClosingBrace
return [name,obrace,args,cbrace]
parseName = many (noneOf "(") >>= \name -> return ("fid",name)
parseOpeningBrace = char '(' >> return ("sym","(")
parseArguments = many (noneOf ")") >>= \name -> return ("args",name)
parseClosingBrace = char ')' >> return ("sym",")")
main = case parse parseFunction "" "hello(some, args)" of
Left error -> print error
Right result -> print result
Вот вывод:
[("fid","hello"),("sym","("),("args","some, args"),("sym",")")]
Я бы действительно предложил вамПодумайте о лучшем представлении анализируемой функции, это может упростить задачу.