Как получить доступ к входному потоку Parsecs напрямую - PullRequest
0 голосов
/ 09 января 2020

Я хочу получить прямой доступ к входному потоку parsecs, что можно сделать с помощью getParserState. Для чтения из потока предусмотрен метод uncons. Однако я сталкиваюсь (как обычно) с проблемой типа. так что это моя функция синтаксического анализа:

myParser :: (Stream s m Char) => ParsecT s (ShiftedState u s) m String
myParser = do
  s <- P.getParserState
  let i = stateInput s
  let x = uncons i
  return ""

, и я получаю следующую ошибку.

Could not deduce (Stream s m0 Char)
        arising from a use of ‘uncons’

И проблема просто в том, что я не совсем знаю, что именно означает ошибка , Я думаю, что uncons работает в основной монаде, а не в монаде ParsecT. Но я не знаю, как его поднять (?).

В основном я хотел бы знать, как я могу использовать uncons и читать из потока. Теперь, пожалуйста, не беспокойтесь о том, что должен сделать это ... это в основном я понимаю, как работают монады xD

1 Ответ

1 голос
/ 09 января 2020

Вот что происходит: uncons должен работать в какой-то монаде. Вы можете увидеть это по типу подписи: uncons :: Stream s m t => s -> m (Maybe (t, s)). Но вы просто делаете let x = uncons i - так что x - это вычисление monadi c, которое возвращает результат uncons i, но вы не указали , который monad в этом вычислении monadi c работает внутри. Вы случайно знаете, что вы 'хотите' uncons i бежать внутри вашей монады m (что удовлетворяет Stream s m Char), но GH C не знает этого. Итак, GH C делает предположение, что здесь uncons i :: m0 (Maybe (t, s)), где m0 - произвольная монада. Таким образом, GH C создает ошибку, которую вы видите, поскольку uncons требует, чтобы ограничение Stream s m0 Char было выполнено, чтобы использовать его, но это ограничение не обязательно выполняется для любого случайного m0.

Как это можно решить? Ну, вы уже знаете, что все эти вычисления имеют тип ParsecT s (ShiftedState u s) m Char, а m удовлетворяет экземпляру Stream s m Char. И, как выясняется, есть функция lift :: Monad m => m a -> ParsecT s u m a, которая «поднимает» вычисление monadi c m a до вычисления Parse c ParsecT s u m a. Таким образом, вы можете просто переписать свою функцию следующим образом:

myParser :: (Stream s m Char) => ParsecT s (ShiftedState u s) m String
myParser = do
  s <- P.getParserState
  let i = stateInput s
  x <- lift (uncons i)
  return ""

Я не проверял ее, но это должно работать, если я не допустил ошибок.

(Другое решение состоит в том, чтобы просто дать x сигнатуру типа:

let x :: m (Maybe (Char, s))
    x = uncons i

Это заставит x иметь нужный вам тип. Теперь GH C может посмотреть и увидеть, что m и s все удовлетворяют соответствующим ограничение, поэтому не приводит к этой ошибке. Но для компиляции требуется расширение языка ScopedTypeVariables, и оно гораздо менее элегантно, чем в предыдущем решении.)

...