Maarten wrote:
For a project involving I use some partially defined node (in this
case a simple record, in my project state transformers) in which the
defined part is common to all nodes, and the custom part is different
for each node. They have to become anonymous so I can put them in a
list of connections from each node to another.
For some reason GHC complains of 'ambigous type variable' in the code
below. The thing is, part of the code may be undefined, but since I'm
(explicitly) not using that part, why would GHC care? Are there other
solutions to this problem? Any pointers or comments appreciated.
-- data structure with custom and common part
data Node cust = Node cust Common
deriving (Show,Typeable)
-- anonymous data structure to put use in list
data AN = forall ar. (Show ar, Typeable ar) => AN ar
instance Show AN where
show (AN an) = "AN (" ++ show an ++ ")"
-- common part
data Common = Common Integer
deriving (Show,Typeable)
data Custom = Custom Integer
deriving (Show,Typeable)
data Custom2 = Custom2 Integer
deriving (Show,Typeable)
-- extract common part, ignoring type of custom part
getCommon :: forall gc. (Node gc) -> Common
getCommon (Node cust com) = com
main = do
let a = AN (Node (Custom 5) (Common 10))
let b = case a of (AN a') -> getCommon (case (cast a') of Just a''
-> a'')
putStrLn $ "ok:" ++ show b
Hi Maarten -
The problem is that AN is far too general. The compiler can't tell that
you've wrapped a Node, so the call to getCommon will fail to typecheck.
Even if the compiler did know, by some other means, that a Node had been
wrapped, Haskell doesn't support true existentials, so the type signature
for getCommon doesn't do what I think you mean ie:
getCommon :: forall gc. (Node gc) -> Common
is the same as writing:
getCommon :: Node gc -> Common
whereas you'd really need an existential:
getCommon :: (forall gc. Node gc) -> Common
The fact that gc is not used in the definition of getCommon doesn't matter,
since the type system has to just use the same rules for type inference
regardless of the content of the function. In other words, without true
existentials, or some other extension to the type system, there is no way to
propagate the fact that the actual binding for a type variable is never
required. Also, AFAIK there is no guarantee that Node Int Common and Node
String Common would always be laid out in memory in the same way - the
compiler is allowed to use special optimized layouts for particular
instantiations of cust (even though it probably won't be clever enough to do
this at the moment in Haskell implementations).
I suggest you wrap the custom part separately instead of wrapping the whole
Node eg:
data Custom = forall cust. ICusom cust => Custom cust
data Node = Node Custom Common
where the ICustom class is whatever class you need to be able to do anything
useful with cust.
Alternatively, you could wrap the custom part within the node as in:
data Node = forall cust. ICustom cust => Node cust Custom
getCommon :: Node -> Common
getCommon (Node cust com) = com
Regards, Brian.
--
Logic empowers us and Love gives us purpose.
Yet still phantoms restless for eras long past,
congealed in the present in unthought forms,
strive mightily unseen to destroy us.
http://www.metamilk.com
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe