
Dylan Thurston writes:
It seems like there are two things you want to do with these functional closures: save them to disk, and run them as functions. Why not combine these two into a type class?
Dylan, This is the kind of thing I'd like to do, but I can't see how to do it. (Not that I'm claiming it's impossible, I'd played with Haskell on and off for a couple of years now, but I'm a long way from being an expert.) class StoreableFunc1 a where store :: a -> String unstore :: String -> a apply :: ?? -- What type here?? Probably a multi-parameter class would be appropriate, but again I can't really see how: class StorableFunc2 (f a) where store :: f a -> String unstore :: String -> f a apply :: f (b -> c) -> b -> f c -- Would need a type roughly like this -- But this is obviously wrong Of course, I could do: class StorableFunc3 (f a) where store :: f a -> String unstore :: String -> f a unwrap :: f a -> a But then, once you chose to apply one value a function, it is no longer storable. I have actually managed to hack something together which satisfies most of my requirements. I have a type (ExtFunc a) which is an instance of Read and Show. There are the following functions: apply :: forall b a. (Show a) => ExtFunc (a -> b) -> a -> ExtFunc b unwrap :: forall a. ExtFunc a -> a So, ExtFuncs can be used just like functions, and can be shown and read, even when partially applied, which I like. The Show a context on apply is obviously because the argument has to be shown when showing a partially applied value. For example, TestTaggedFunc.test is a function which adds it's two parameters. *TaggedFunc> TestTaggedFunc.test 1 2 3 I've associated the tag "test" with the function test, so the string "ExtFunc{test}" when read, produces the test function wrapped up in an ExtFunc: *TaggedFunc> let x = read "ExtFunc{test}" :: ExtFunc (Int -> Int -> Int) *TaggedFunc> x ExtFunc{test} (Note that unwrap x is exactly TestTaggedFunc.test) Can partially apply the function and it's still showable: *TaggedFunc> let y = apply x 1 *TaggedFunc> y ExtFunc{test 1} Fully applying the function still shows the parameters: *TaggedFunc> let z = apply y 2 *TaggedFunc> z ExtFunc{test 1 2} But we can unwrap the actual value: *TaggedFunc> unwrap z 3 The main problem it that all the exported functions have to be collected together in the module which has the instance of Read (ExtFunc a), meaning that if a module wants to both export functions for use in ExtFunc and read ExtFuncs, there is a mutual recursion. It also uses Dynamic (to allow all the functions exported from all modules to appear in a single list), so there's potential for types not to match up etc, although I think this isn't much worse than the potential failure of any read due to the type not matching the value in the string. (But I'm not really sure because I've only just discovered the Dynamic module.) Comments appreciated. Regards, Nick