Binary instance for Static Pointers

97 Views Asked by At

I have the following data type

data Foo a b = A (StaticPtr (a -> b)) deriving (Generic, Typeable)

I want to generate the Binary instance for this type so I can use this function on a remote node.

However, using automatic Binary instantiation doesn't work here:

instance (Binary a, Binary b) => Binary (Foo a b)

This results in

• Could not deduce (Binary (StaticPtr (a -> b)))
    arising from a use of ‘binary-0.8.5.1:Data.Binary.Class.$dmput’
  from the context: (Binary a, Binary b)
    bound by the instance declaration
    at /Users/abhiroop/Haskell/snape/app/Spec.hs:23:10-49
• In the expression:
    binary-0.8.5.1:Data.Binary.Class.$dmput @Foo a b
  In an equation for ‘binary-0.8.5.1:Data.Binary.Class.put’:
      binary-0.8.5.1:Data.Binary.Class.put
        = binary-0.8.5.1:Data.Binary.Class.$dmput @Foo a b
  In the instance declaration for ‘Binary (Foo a b)’


• Could not deduce (Binary (StaticPtr (a -> b)))
    arising from a use of ‘binary-0.8.5.1:Data.Binary.Class.$dmget’
  from the context: (Binary a, Binary b)
    bound by the instance declaration
    at /Users/abhiroop/Haskell/snape/app/Spec.hs:23:10-49
• In the expression:
    binary-0.8.5.1:Data.Binary.Class.$dmget @Foo a b
  In an equation for ‘binary-0.8.5.1:Data.Binary.Class.get’:
      binary-0.8.5.1:Data.Binary.Class.get
        = binary-0.8.5.1:Data.Binary.Class.$dmget @Foo a b
  In the instance declaration for ‘Binary (Foo a b)’

How do I auto generate the Binary instance here?

2

There are 2 best solutions below

0
On BEST ANSWER

Li-yao Xia's answer is correct. But I had to change my data types, in general, to pass them remotely. I am writing my changes here so it might be useful if someone wants to send a function remotely, there isn't many resources on this online.

So instead of having

data Foo a b = A (StaticPtr (a -> b))

I have changed my data types to look like this:

data Foo a b = A (a -> b)

or to simplify

data Foo f = A f

Here f is the function I want to send remotely.

So taking a simple example of a function like (+ 1) and imagine I want to map this over a list [1,2,3] which is present remotely. My code becomes like this:

main :: IO [Int]
main = do
let list = [1,2,3]
    a = static (A (+ 1)) :: StaticPtr (Foo (Int -> Int))
    t = staticKey a
    -- assuming you sent t to the remote node
    -- code on the remote node
    x <- unsafeLookupStaticPtr t
    case x of
      Just sptr -> case deRefStaticPtr sptr of
                         A f -> return $ map f list
                         _   -> error "Task undefined"
      Nothing -> error "Wrong function serialized"
2
On

You can serialize a StaticPtr as a Fingerprint via staticKey and deserialize it via unsafeLookupStaticPtr below it.

You can't define a Binary instance for StaticPtr (even if you wrap it in a newtype to avoid orphans) because the lookup cannot be done purely. But you can still define and use the serializer and deserializer as regular, nonoverloaded functions.