Frederik, Thanks for the challenge.
I didn't get some of the bits about your application scenario though. (What did you mean by the type Pred? Why a list in the result of solve? How did you model typed logical variables? With GADTs, phantoms? ... Perhaps send more code, if you want to discuss this topic more.) So I hope that the attached make sense to you. I do believe so. I have coded a function that converts a term "t Maybe a" to a term "t Id a", where I assume that: - "t" is the Haskell type that may involve Maybe/Id "spots". - Maybe/Id spots for variables are wrapped in a dedicated datatype Spot, - "a" is the type of the term with regard to some custom type system. - The custom type system is model as a class Term. Here is the conversion function: force :: ( Data (t Maybe a) , Data (t Id a) , Term t Maybe a , Term t Id a ) => t Maybe a -> t Id a force = fromJust . tree2data . data2tree This example assumes that all Maybe spots are actually Just values. Clearly, you can do some error handling in case this cannot be assumed. You could also make the Maybe-to-Id conversion part of the traversal that resolves "holes". This is not the challenge, the challenge was indeed to traverse over a term and to "get the types right" when replacing subterms of type Maybe x by subterms of type Id x. The actual type conversion relies on going through the universal Tree datatype. We use "Tree Constr" as the type of an intermediate value. (We could also use "Tree String" but this would be more inefficient. BTW, we take here dependency on the invariant that constructors in Constr are polymorphic. So SYB's reflection is nicely generic; compare this with Java.) When encountering spots during trealization, they are converted from Maybies to Ids. Then, a subsequent de-trealization can do its work without any ado. The deep trealization solves the problem of exposing these type changes to the type of gfoldl. (Amazingly, one might say that the type of gfoldl is just not general enough!) I guess I should admit that: - We temporally defeat strong typing. - We make the assumption that all occurrences of Spot are to be converted. - That is, we don't quite track the type parameter for Maybe vs. Id. - This is a bit inefficient because of going through Tree Constr. So I am willing to summarize that this is potentially a sort of a (cool) hack. Code attached. Ralf P.S.: The extension you propose seems to be a major one. Perhaps you could look into the TH code for SYB3 (ICFP 2005) to see whether this can be automated. This sort of discussion calls for kind polymorphism once again. > -----Original Message----- > From: [EMAIL PROTECTED] [mailto:haskell-cafe- > [EMAIL PROTECTED] On Behalf Of Frederik Eaton > Sent: Sunday, August 28, 2005 9:36 PM > To: haskell-cafe@haskell.org > Subject: [Haskell-cafe] generics question, logical variables > > Hi all, > > I'm trying to write something like a generic fmap, or a generic > natural transformation. The application is this. I have a typed > logical variable library which produces arbitrary terms with values of > type "Var a", which are references to a value of type "Maybe a", and I > want to write a "solve" function which replaces these values with > instantiated versions of type "Id a" where > > newtype Id a = Id a > > . Furthermore I want this to be reflected in the type of the generic > term: > > solve :: Pred (t Var) -> [t Id] > > so if I have a type like > > data Entry k = Entry (k String) (k Int) > > then I can write some constraint equation with values of type "Entry > Var", and get back values of type "Entry Id" - in other words, objects > where the unknowns are statically guaranteed to have been filled in. > > I looked at the generics library. I may be mistaken, but it seems that > it doesn't have what I need to do this. The problem isn't the mapping, > it's creating a new type which is parameterized by another type. The > only options for creating new types are variations on > > fromConstr :: Data a => Constr -> a > > but what is needed is something like > > fromConstr1 :: Data1 a => Constr1 -> a b > > With something like that it should be possible to define: > > gmapT1 :: (forall b . Data1 b => b l -> b m) -> a l -> a m > > Does this make sense? Here I would be treating all instances of Data > as possibly degenerate instances of Data1 (which just might not depend > on the type variable). > > If it seems like a good idea, I would be interested in helping out > with the implementation. > > Frederik > > -- > http://ofb.net/~frederik/ > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe
PseudoFmap.hs
Description: PseudoFmap.hs
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe