微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将类型为MonadIO的类的实例提升为转换后的monad

如何解决将类型为MonadIO的类的实例提升为转换后的monad

作为我需要记录单子计算数据的程序的一部分,我试图定义一个类以使其更加方便。

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 ()

我想做的一件事是在“较高”的monad中定义getput,因为在IO中无法访问某些数据。对于更简单的数据,例如Storable的实例,IO就足够了。我想将基本实例保留在“最低”的monad中,但允许将操作提升到任何“较高” 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则不再起作用。我认为可以通过重叠实例来解决此问题,但我想尽可能避免这种情况。有什么办法可以做到这一点?

解决方法

您只需写出所需的额外约束:

func :: (Serial m a,Serial m Int32) => Handle -> a -> m ()
func h a = put h (0::Int32) >> put h a

(我认为这需要-XFlexibleContexts。)

如果这使签名变得笨拙,则可以将约束归为一个“约束同义词类”:

class (Serial m a,Serial m Int32,Serial m Int64,...)
       => StoSerial m a
instance (Serial m a,...)
       => StoSerial m a

func :: StoSerial m a => Handle -> a -> m ()
func h a = put h (0::Int32) >> put h a

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?