Functional dependencies and Constructor Classes
Martin Sulzmann
sulzmann@comp.nus.edu.sg
Mon, 18 Nov 2002 17:32:13 +0800 (GMT-8)
Hi,
I was wondering whether other people made similiar observations.
Functional dependencies seem to be expressiveness enough to encode
some of the kinding rules required for Constructor Classes.
Take a look at the Haskell code below
(runs under hugs -98 or ghci -fglasgow-exts-fallow-undecidable-instances)
Martin
-- An alternative to constructor classes
module Fmap where
{- Instead of
class Functor f where fmap :: (a->b)->(f a->f b)
use
-}
class Fmap a b fa fb | a fb -> b fa,
b fa -> a fb,
fa fb -> a b
where fmap2 :: (a->b)->(fa -> fb)
{- We require:
(1) fmap2 transforms a function into another function,
i.e. fmap2's type should always be of shape (a->b)->(fa->fb)
(2) b, fa uniquely determine a and fb
(3) a, fb " b and fa
(4) fa, fb " a and b
Note that (1) is enforced by the class definition. (2)-(4) are enforced by FDs.
My guess/conjecture is that the above axiomatization of functors is equivalent to the
one found in Haskell98.
-}
-- some Examples
{- The following is a variation of an example taken from Mark Jones original paper
"A System of Constructor Classes: Overloading and Implicit Higher-Order Polymorphism".
He used this example to motivate the introduction of constructor classes. The example
is type correct using the alternative formulation of functors.
-}
cmap :: (Fmap a b fb1 fb, Fmap a1 b1 fa fb1) =>
(a1 -> b1) -> (a -> b) -> fa -> fb
cmap f g = (fmap2 g) . (fmap2 f)
-- identity functor
instance Fmap a a a a where fmap2 h = h
-- functor composition
-- Instance is not allowed, cause leads to undecidable type inference
{-
instance (Fmap a b c d, Fmap e f a b) => Fmap e f c d
where fmap2 h = fmap2 (fmap2 h)
-}
comp :: (Fmap fa1 fb1 fa fb, Fmap a b fa1 fb1) =>
(a -> b) -> fa -> fb
comp h = fmap2 (fmap2 h)