[Haskell-cafe] Re: Storing functional values

nickgrey at softhome.net nickgrey at softhome.net
Mon Feb 2 16:26:23 EST 2004


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 


More information about the Haskell-Cafe mailing list