PSQueue的实例二进制

时间:2016-09-25 23:24:56

标签: haskell

我想从容器中为优先排序队列创建二进制实例。我正在使用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的二进制实例?

1 个答案:

答案 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不能为我做这项工作?

为了让GHC能够为你推导出正确的Binary实例,它依赖于一个名为Generic的特殊类,它提供有关不同构造函数中包含的数据的高级信息。在启用DeriveGeneric标志的情况下派生此类(如ReadShowEq等)。但是,由于PSQ 派生Generic,我们可能会被卡住。

通常情况下,我们可以提取另一种技巧:启用StandaloneDeriving让我们像往常一样派生,但与data定义分开:

deriving instance (Generic (PSQ k v))

但这确实要求PSQ k v的构造函数是公共的(在这种情况下它们不是),所以我们真的无法导出Generic (PSQ k v)。在这一点上,简单地编写实例就简单得多了。