Я пытаюсь реализовать оболочку Parsec Stream
, которая будет запоминать последний токен uncons
'd, чтобы обеспечить некоторую возможность поиска. Я хочу, чтобы обертка работала с любым экземпляром Stream
. Вот то, что я до сих пор:Использование функциональной зависимости для исключения параметра типа
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
module MStream where
import Text.Parsec
import Control.Monad (liftM)
data MStream s t = MStream (Maybe t) s
instance Stream s m t => Stream (MStream s t) m t where
uncons (MStream _ s) = fmap (\(t, s') -> (t, MStream (Just t) s')) `liftM` uncons s
getPrevToken :: Stream s m t => ParsecT (MStream s t) u m (Maybe t)
getPrevToken = (\(MStream t _) -> t) `liftM` getInput
mstream :: s -> MStream s t
mstream = MStream Nothing
Это работает, но я не люблю носить параметр t
в конструкторе MStream
типа. Разумеется, этого должно быть достаточно, чтобы требовать только параметр s
, поскольку t
может быть получен из s
, пока есть свидетель для Stream s m t
. Я пробовал использовать семейства типов и GADT, но я все время сталкиваюсь с неясными ошибками в отношении неоднозначных переменных типа и неудовлетворенных функциональных зависимостей.
Есть ли способ, чтобы удалить t
из конструктора по MStream
типа, так что я не должен писать:
sillyParser :: Stream s m Char => ParsecT (MStream s Char) u m String
sillyParser = do
t <- getPrevToken
maybe (string "first") (\c -> string $ "last" ++ [c]) t
Я попытался сделать 'StreamDep s t | s -> t' суперкласса 'Stream' и использовать это:' data MStream s = forall t. StreamDep s t => MStream (возможно, t) (m()) s'. Также 'data MStream s = forall m t. Поток s m t => MStream (возможно, t) (m()) s'. Я бы сказал, не стоит боли. – phadej