I'm a Haskell and a Stackoverflow noob, and here's my first & probably quite basic Haskell question.
module M where
import Data.HList
data R r a
r1 = undefined :: R a Int
r2 = undefined :: R a Double
rPair :: R r a -> R r b -> (R r a, R r b)
rPair = (,)
rp = rPair r1 r2
This makes sense, even if r1 & r2 are polymorphic in r rPair aligns their r type in accordance with the type signature. Is there a technical term for this 'alignment'?
class HList l => RList r l
instance RList r HNil
instance RList r l => RList r (HCons (R r a) l)
rCons :: RList r l => R r a -> l -> (HCons (R r a) l)
rCons = hCons
rc = rCons r1 (rCons r2 hNil)
rCons works great if the R's passed are monomorphic in r, constraining the list's r type as desired. but if they are polymorphic in r it does not align them the way rPair does, and gives an error (defining rc above).
No instance for (RList r (HCons (R r1 Double) HNil))
I have a vague intuition as to why this is the case, but my question is in two parts. Could somebody clearly explain the phenomenon? How would I write an rCons such that the following would hold?
r1 = undefined :: R a Int
r2 = undefined :: R a Double
rc :: HCons (R a Int) (HCons (R a Double) HNil)
rc = rCons r1 (rCons r2 hNil)
Thanks, _c
To answer your second question, you can use type equivalence constraint (from TypeFamilies extension) to relax your
RList
instance definition:Now your
rc
will be inferred to the desired type.I don't think I can 'clearly explain' the phenomenon though (somebody surely will), but it's obvious that the difference between
rPair
andrCons
is that while the former bindsr
type of both arguments to the same type variable, the later doesn't: the second argument is justl
constrained with that there should be some instance ofRList
for thatl
). Since there is no type signature forrc
(note that if you provide one your original example typechecks) and r1 and r2 have polymorphic, not equivalent,r
's , compiler is trying to find an instance definition forRList r (HCons (R r1 Double) HNil)
(r
comes from the 1st argument andr1
- from the 2nd) and fails to do so. With type equivalence constraint we define an instance of RList with two distinctr1
andr2
with the only condition that these needs to be equivalent, so it looks like GHC binds them to the same polymorphic type variable when resolving instance ofRList
forl
.