Dynamic typing of polymorphic functions

Hi all, As some of you might remember I'm working on a EDSL which models process networks (A process can simply be viewed as a box which has a number of input and output signals and makes computations over them). A simple example of the processes implemented is MapSY, which is similar to Haskell's well-known map function. It takes a signal and a processing function as arguments and applies that function the signal. Following Lava's approach, a specifically designed Signal type hides and "secretly" forwards the structure of the network. Such structure is logically an untyped graph. For that reason, the processing functions associated to the different processes are kept in Dynamic form. A very simplified implementation could be: ------ import Data.Typeable import Data.Dynamic -- the phantom type parameter makes signal typing consistent newtype Signal a = Signal PrimSignal newtype PrimSignal = PrimSignal (Proc (PrimSignal)) data Proc input = MapSY Dynamic -- The processing function input -- The process input -- the rest of the processes are omitted eval :: Proc Dynamic -> Dynamic -- evaluates the output of a process for one input eval (MapSY dynF dynIn) = dynApp dynF dynIn -- the map process constructor mapSY :: (Typeable a, Typeable b) => (a -> b) -> Signal a -> Signal b mapSY f (Signal primSig) = Signal (PrimSignal (MapSY (toDyn f) primSig)) ----- OK, If you managed to read until this point, you might have noticed that, due to the monomorphism restriction implied by Data.Typeable, it is impossible to build polymorphic processes. The approach works nicely for monomorphic processes though: add1 :: Signal Int -> Signal Int add1 = mapSY ((+1) :: Int -> Int) mapSndInt :: Signal (Int, Int) -> Signal Int mapSndInt = mapSY (snd :: (Int, Int) -> Int) But it does not work for building polymorphic processes. The following process would be really useful but its compilation obviously fails: mapSnd :: Signal (a, a) -> Signal a mapSnd = mapSY snd Could not deduce (Typeable a) from the context () arising from a use of `mapSY' Possible fix: add (Typeable a) to the context of the type signature for `mapSnd' Again, due to the monomorphism restriction of the Typeable class, the compiler's suggestion of adding a Typeable context didn't work. (Well, strangely enough, adding the "Typeable a" constraint hushed GHC but an error was instead triggered at runtime). I must admit I'm totally stuck with this problem. My two options are: 1) Forcing the user to define mapSnd & friends for each combination of types (which can hardly be considered an acceptable solution) 2) Think of a change in the internal representation of signals which made polymorphic processes possible. Polymorphic processes don't have to be necessarily definable by the user. They should be happy enough with a few polymorphic primitives (mapSnd would be one of them). * Maybe an implementation of unsafe dynamics using unsafeCoerce which allowed applying polymorphic functions to monomorphic values for specific safe cases? I would really appreciate any suggestions or remarks regarding my problem/design. Thanks in advance, Alfonso Acosta

Hi
OK, If you managed to read until this point, you might have noticed that, due to the monomorphism restriction implied by Data.Typeable, it is impossible to build polymorphic processes.
Tom Shackell had similar issues with passing code around at runtime. As a result Yhc contains the Yhc.Dynamic module which gives you all polymorphic dynamic typing. It's integrated into the compiler and runtime system. I don't think anything is written up on it yet, sadly. I'm not sure it will be much use to you, other than to say you aren't the first to have these thoughts. Thanks Neil

On Dec 19, 2007 9:13 PM, Neil Mitchell
OK, If you managed to read until this point, you might have noticed that, due to the monomorphism restriction implied by Data.Typeable, it is impossible to build polymorphic processes.
Tom Shackell had similar issues with passing code around at runtime. As a result Yhc contains the Yhc.Dynamic module which gives you all polymorphic dynamic typing. It's integrated into the compiler and runtime system.
Thanks for your answer Neil.
From your description it _seems_ to be exactly what I need (I coudn't reallly figure it out form the sources since its implementation seems to rely on Yhc internals I totally ignore). Are there any examples of use available?
Even if Yhc.Dynamic turns out to be what I need, my implementation unfortunately depends on Template Haskell. Could any GHC guru point out if this would be feasible (and how complicated) to implement in GHC? Thanks, Fons

Alfonso Acosta wrote:
2) Think of a change in the internal representation of signals which made polymorphic processes possible. Polymorphic processes don't have to be necessarily definable by the user. They should be happy enough with a few polymorphic primitives (mapSnd would be one of them).
I am not sure if this is applicable to your problem, but in GHC you can wrap polymorphic values in a newtype using higher-rank polymorphism, like in newtype WrapId = WrapId { unWrapId :: (forall a. a -> a) } deriving Typeable You can then use toDyn . WrapId to wrap 'id' into a Dynamic and unWrapId . flip fromDyn (error "wrong type") to unwrap it. Cheers Ben
participants (3)
-
Alfonso Acosta
-
Ben Franksen
-
Neil Mitchell