Jared Warren wrote:
I'm doing some work with heterogeneous sets as provided by the HList library <http://homepages.cwi.nl/~ralf/HList/>. My code uses projections of sets internally and I keep running into the open-world assumption when I ask the type checker to infer the result of projections. For example (in ghci):
*> hProject hNil No instance for (HProject HNil l')
...When obviously the only valid projection from the empty set is the empty set.
So what I'm wondering: is it possible to rewrite HProject in such a way as to allow the type checker to infer that the only possible projections from a list are its (non-proper) sublists?
If the inference is unique, then of course, we _can_ infer that the empty list can only be projected onto the empty list. However any non-empty list can be projected in several ways. How do we infer this ambiguous result? Either we have to specify which projection result we want, and the typechecker will tell us if that is possible. Or we obtain the powerset of a list -- and then enumerate it. The current HProject is written with the first approach in mind:
class HProject l l' where hProject :: l -> l'
As we can see, there are no functional dependencies on the class -- as there can't be, in general. A list can, in general, be projected in many ways (and given a projection, there can be many lists it can be obtained from). So, we have to be explicit: which list is to project into what. In general, that is the best one can do, right? There is however, a special case: the empty list. The empty list can only be projected one way -- and, so we would like the typechecker to infer that (rather then wait for us to supply the result and then check it). If that behavior is desirable, it can be obtained. The key is the ability to specify functional dependencies on a per-instance basis. Here's the complete code
{-# OPTIONS -fglasgow-exts #-} {-# OPTIONS -fallow-undecidable-instances #-} -- Look, Ma! No overlapping instances!
module Foo where
import CommonMain hiding (HDeleteMany, hDeleteMany, TypeCast, typeCast, HProject, hProject) import TypeCastGeneric2 import TypeEqTTypeable import TypeEqBoolTTypeable import TTypeable
class HProject l l' where hProject :: l -> l'
instance TypeCast HNil l' => HProject HNil l' where hProject _ = typeCast HNil instance HProject (HCons a r) HNil where hProject l = HNil instance ( HList l', HOccurs' e (HCons a r), HProject (HCons a r) l') => HProject (HCons a r) (HCons e l') where hProject l = HCons (hOccurs' l) (hProject l)
list1 = (HCons 'a' (HCons True HNil))
test1 = hProject list1 :: HNil test2 = hProject list1 :: (HCons Char HNil) test3 = hProject list1 :: (HCons Bool HNil)
-- NB: No explicit type of the result given. The typechecker _does_ -- infer it test4 = hProject HNil
If the inference is unique, then of course, we _can_ infer that the empty list can only be projected onto the empty list. However any non-empty list can be projected in several ways. How do we infer this ambiguous result? Either we have to specify which projection result we want, and the typechecker will tell us if that is possible. Or we obtain the powerset of a list -- and then enumerate it.
But is there no way things could be changed so we can write (to use an example without projection to HNil): *> hProject (hProject (hCons hZero hNil)) :: HCons HZero HNil
Jared Warren wrote:
But is there no way things could be changed so we can write (to use an example without projection to HNil):
*> hProject (hProject (hCons hZero hNil)) :: HCons HZero HNil _______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Not surprising as this is just like doing: read (show x)... Project extracts elements of the return-type, so the inner project is unconstrained. Of course this is completely pointless as: *> hProject (hCons hZero hNil) :: HCons HZero HNil is what you want. Infact you can almost say that hProject . hProject = hProject? Keean
participants (3)
-
Jared Warren -
Keean Schupke -
oleg@pobox.com