Я пытаюсь реализовать оболочку Parsec Stream
, которая будет помнить последний токен uncons
, чтобы обеспечить некоторую возможность просмотра назад. Я хочу, чтобы оболочка работала с любым экземпляром 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 (Maybe t) (m ()) s
. Такжеdata MStream s = forall m t. Stream s m t => MStream (Maybe t) (m ()) s
. Я бы сказал, не стоит боли. - person phadej   schedule 17.07.2015