
On Fri, Nov 12, 2010 at 4:24 AM, Ketil Malde
IMO, it's morally different, you're now operating on a file, and you shouldn't rely on the contents being predictable. You can make the sin-bin argument that IO can do anything, but I think there's a moral distinction between
serialize :: a -> IO ByteString x <- serialize f
and
serialize :: a -> Opaque store :: Opaque -> FilePath -> IO ()
Any distinction here is mostly at the level of API design and informal semantics; I'm inclined to agree with your preference, but as far as impacts on the formal semantics of pure code go, these are essentially equivalent.
You could probably already snarf chunks of the heap and dump them to file.
Yep, and this is pretty much the reason, taken to its logical conclusion, why almost all bets are off about what IO computations can potentially do.
I suppose one could object that this isn't actually serializing anything at all; to which I would respond that, in pure code, how do you expect to tell the difference?
Nice one :-)
I guess the real question is what are the useful, pure operations on an opaque type that can contain arbitrary functions.
I would be very surprised if there were any that couldn't just as well be done on the function directly. Even extracting type information could be problematic if done incorrectly! Consider a function (inspectType :: Opaque -> Serialization.Type), where the Show instance for Type produces an approximation of the type signature the function was declared with. Reasonable? Nope, we just broke everything. Imagine a function taking an argument of type ((a, a) -> a). If by serializing the argument it can recover the declared type signature it could distinguish between fst and ((\(x, _) -> x) :: forall a. (a, a) -> a), which again opens the door to non-parametric behavior. On the other hand, (inspectType :: Opaque -> Data.Typeable.TypeRep) would probably be safe, because it supports only monomorphic types. - C.