Как часть программы, в которой мне нужно регистрировать данные монадических вычислений, я пытаюсь определить класс, чтобы сделать это более удобным.
module Serial where
import Data.Int
import Data.IORef
import System.IO
import Control.Monad.Trans
import Foreign.Ptr
import Foreign.Marshal
import Foreign.Storable
class MonadIO m => Serial m a where
get :: Handle -> m a
put :: Handle -> a -> m ()
Одна из вещей, которые я хотел бы сделать, - это определить get
и put
в «более высокой» монаде, поскольку некоторые данные недоступны в IO
. Для более простых данных, например, экземпляров Storable
, достаточно IO
. Я хотел бы сохранить базовые экземпляры в самой «низшей» возможной монаде, но разрешить перенос действий на любой «более высокий» MonadIO
экземпляр.
instance (Serial m a, MonadIO (t m), MonadTrans t)
=> Serial (t m) a where
get = lift . get
put h = lift . put h
instance Storable a => Serial IO a where
get h = alloca (\ptr
-> hGetBuf h ptr (sizeOf (undefined :: a))
>> peek ptr)
put h a = with a (\ptr
-> hPutBuf h ptr $ sizeOf a)
Идея состоит в том, чтобы включить такие функции, как
func :: Serial m a => Handle -> a -> m ()
func h a = put h (0::Int32) >> put h a
где экземпляр в IO
может быть объединен с экземпляром в любом MonadIO
. Однако с моим текущим кодом GHC не может определить экземпляр для Serial m Int32
. В частном случае подъема IO
эту проблему можно решить с помощью liftIO
, но если базовый тип t IO
, это больше не работает. Я думаю, что это можно решить, перекрывая экземпляры, но я бы хотел избежать этого, если это возможно. Есть ли способ добиться этого?
Serial m Int32
к ограничениямfunc
? Похоже, что здесь можно поступить правильно. - person leftaroundabout   schedule 03.10.2020Serial
дляt m
немедленно отправит вас на перекрывающуюся территорию. Лучше использоватьDefaultSignatures
, чтобы дать определения по умолчанию, основанные на этой идее. - person dfeuer   schedule 04.10.2020default get :: (m ~ t n, MonadTrans t, Serial n a) => Handle -> m a
с определением по умолчаниюget = lift . get
. - person dfeuer   schedule 04.10.2020