It's very easy to state this problem without enough details and mislead people into providing a solution for a different problem, so I'll try to include all the information and use-case. I need a function that can store a value in a concrete opaque type. I know the type of the value when I store it, and I know the type of the value when I extract it, insofar as I know the type inclusive of a class constraint context. But the container must store many different things at once. Given that I know the type of the thing when I store it and when I extract it, there ought to be a “safe’ way to do this, in the same way that Data.Dynamic is “safe”.
The use-case is I want to store a table of IO-like actions in an opaque like [(Name,Dynamic)] and I write into it statically, e.g. in GHCi. The reason is due to this approach: go_ref = newIORef go_ go_ = putStrLn "Hello, World!" go = do go' <- liftIO $ readIORef go_ref go' main = forkIO $ forever $ go then in GHCi I writeIORef go_ (putStrLn "What's up?") then go will now start printing "What's up?" This works now, I can do this presently. However, I want to write this as a core-to-core translation as a ghc-plugin. I want the definition go = putStrLn "Hello World!" to be translated to what I wrote above. Core cannot generate new names to be exported from a module, so go_ is now gone. So how does the `go' function read and write the IORef? With a table: table = unsafePerformIO $ newIORef [("go",Dynamic go_ref)] Hurrah! I can now put table in some module like DynamicUpdate.table and then read/write to it from Core in the generated definition of go. Done. But how do I update it from the GHCi REPL? What follows is where I'm stuck. So with Data.Dynamic, I have: toDyn :: Typeable a => a -> Dynamic With toDyn I can store concrete values and functions and then extract them: λ> fmap ($ 12) (fromDynamic (toDyn ((*2) :: Int -> Int)) :: Maybe (Int -> Int)) Just 24 But the problem with toDyn is that it can only store concrete values due to the Typeable constraint. So then I turn to existentials and unsafeCoerce: λ> data Anything = forall a. Anything a λ> let x = Anything id λ> case x of Anything (unsafeCoerce -> (id' :: Int -> Int)) -> id' 123 123 Great, I was able to store a value which contained non-concrete types. But now consider the case of a value with type-class polymorphic type in it: y = Anything (print :: Show a => a -> IO ()) Which cannot be type checked, because the Show instance is ambiguous. So you might propose to use rank-N types, like this: data Anything = Anything (Show a => a -> IO ()) Now I can store print in there happily. But now the type is not Anything, it's not generic anymore. Maybe I want to store `print', maybe I want to store `readLn'. Dead end. I don't want to have to generate existential wrappers for all functions I might possibly want to store. The support of Constraints in this page http://blog.omega-prime.co.uk/?p=127 makes me think that it's still possible. It would be cool to somehow store a tuple of the dictionary of the constraint and the value itself and then I'd later be able to extract it. But I'm finding it difficult developing anything even simple. Any ideas/help appreciated! _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe