我想从容器中为优先排序队列创建二进制实例。我正在使用lts-7.0
如果Test.hs是
import Data.Binary
import Data.PSQueue
instance Binary a => Binary (PSQ a Int)
运行
stack ghci
:set -XFlexibleInstances
:load Test.hs
导致混淆错误消息。
~> :load Test.hs
[1 of 1] Compiling Main ( Test.hs, interpreted )
Test.hs:4:10: warning: [-Wdeferred-type-errors]
• Could not deduce (GHC.Generics.Generic (PSQ a Int))
arising from a use of ‘binary-0.8.3.0:Data.Binary.Class.$dmput’
from the context: Binary a
bound by the instance declaration at Test.hs:4:10-39
• In the expression: binary-0.8.3.0:Data.Binary.Class.$dmput
In an equation for ‘put’:
put = binary-0.8.3.0:Data.Binary.Class.$dmput
In the instance declaration for ‘Binary (PSQ a Int)’
Test.hs:4:10: warning: [-Wdeferred-type-errors]
• Could not deduce (GHC.Generics.Generic (PSQ a Int))
arising from a use of ‘binary-0.8.3.0:Data.Binary.Class.$dmget’
from the context: Binary a
bound by the instance declaration at Test.hs:4:10-39
• In the expression: binary-0.8.3.0:Data.Binary.Class.$dmget
In an equation for ‘get’:
get = binary-0.8.3.0:Data.Binary.Class.$dmget
In the instance declaration for ‘Binary (PSQ a Int)’
Ok, modules loaded: Main
如何让GHC自动派生PSQ的二进制实例?
答案 0 :(得分:3)
不幸的是,您需要为此实际编写自己的Binary
实例。从好的方面来说,在这种情况下这很容易:
import Data.Binary (put, get)
import Data.PSQueue (toAscList, fromAscList, (:->))
instance (Binary a, Binary b, Ord a, Ord b) => Binary (PSQ a b) where
put = put . fmap (\(k :-> v) -> (k,v)) . toAscList
get = fromAscList . fmap (\(k,v) -> k :-> v) <$> get
所有这一切都是在将优先级队列转换为/从二进制文件转换之前/之后将优先级队列转换为键值元组的升序列表。
为了让GHC能够为你推导出正确的Binary
实例,它依赖于一个名为Generic
的特殊类,它提供有关不同构造函数中包含的数据的高级信息。在启用DeriveGeneric
标志的情况下派生此类(如Read
,Show
,Eq
等)。但是,由于PSQ
不派生Generic
,我们可能会被卡住。
通常情况下,我们可以提取另一种技巧:启用StandaloneDeriving
让我们像往常一样派生,但与data
定义分开:
deriving instance (Generic (PSQ k v))
但这确实要求PSQ k v
的构造函数是公共的(在这种情况下它们不是),所以我们真的无法导出Generic (PSQ k v)
。在这一点上,简单地编写实例就简单得多了。