2013-09-29 12 views
5

GHC odrzuca programCzy istnieje jakiś głębszy teoretyczny powód, dla którego GHC nie może wywnioskować tego typu?

{-# LANGUAGE GADTs #-} 
{-# LANGUAGE KindSignatures #-} 
{-# LANGUAGE DataKinds #-} 
{-# LANGUAGE TypeOperators #-} 
import GHC.TypeLits 

data Foo = Foo 
data Bar = Bar 

data (:::) :: * -> * -> * where 
    (:=) :: sy -> t -> sy ::: t 

data Rec :: [*] -> * where 
    RNil :: Rec '[] 
    (:&) :: (sy ::: ty) -> Rec xs -> Rec ((sy ::: ty) ': xs) 

infix 3 := 
infixr 2 :& 

baz :: Num ty => Rec [Foo ::: String, Bar ::: ty] 
baz = Foo := "foo" :& Bar := 1 :& RNil 

--bang :: (String, Integer) 
bang = case baz of 
     (Foo := a :& Bar := b :& RNil) -> (a, b) 

z

Rec2.hs:25:44: 
    Couldn't match type ‛t’ with ‛(String, Integer)’ 
     ‛t’ is untouchable 
     inside the constraints (xs1 ~ '[] *) 
     bound by a pattern with constructor 
        RNil :: Rec ('[] *), 
       in a case alternative 
     at Rec2.hs:25:35-38 
     ‛t’ is a rigid type variable bound by 
      the inferred type of bang :: t at Rec2.hs:24:1 
    Expected type: t 
     Actual type: (ty, ty1) 
    Relevant bindings include bang :: t (bound at Rec2.hs:24:1) 
    In the expression: (a, b) 
    In a case alternative: (Foo := a :& Bar := b :& RNil) -> (a, b) 
    In the expression: 
     case baz of { (Foo := a :& Bar := b :& RNil) -> (a, b) } 

, z dopiskiem typu działa dobrze. Wszystkie odpowiedzi dotyczące niedotykalnych zmiennych typu i GADT, które znalazłem w sieci, zapewniły, że wnioskowanie typu byłoby niemożliwe lub co najmniej nie do rozwiązania, ale w tym przypadku wydaje się oczywiste, że GHC uzyskało typ (String, Integer), po prostu odmawia ujednolicenia.

+0

Jeśli monomorphize 'baz' to działa? –

+0

Nie, nie ma. – barsoap

Odpowiedz

4

Może oryginalny GADT może być cukier za coś, co nie korzysta GADTs jak poniżej (które działa):

{-# LANGUAGE DataKinds #-} 
{-# LANGUAGE TypeFamilies #-} 
{-# LANGUAGE TypeOperators #-} 
import GHC.TypeLits 

data Foo = Foo 
data Bar = Bar 

data (:::) sy t = (:=) sy t 

data RNil = RNil 
data (:&) a b = a :& b 

type family Rec (xs :: [*]) :: * 
type instance Rec (x ': xs) = x :& Rec xs 
type instance Rec '[] = RNil 

infix 3 := 
infixr 2 :& 

baz :: Num ty => Rec [Foo ::: String, Bar ::: ty] 
baz = Foo := "foo" :& Bar := 1 :& RNil 

bang = case baz of 
     (Foo := a :& Bar := b :& RNil) -> (a, b) 
+0

To jest * bardzo * dobra sugestia i zamierzam się bawić i zobaczyć, jak to współdziała z resztą moich planów, ale tak naprawdę nie odpowiada na moje pytanie, chociaż:) – barsoap

+0

Hmm. Jedną z konsekwencji tego jest to, że wnioskowany typ dla "baz" teraz nie jest ładnym 'Rec' z jego elementami wymienionymi jako parametry typu, jak w np. winyl, ale lista poziomów typu a la HList, rekordy itp. Które jest rzeczą, której zdecydowanie chcę, poświęciłbym dla niej dopasowywanie wzorców. Wszystko działa dobrze z rodziną danych, która w końcu może być tym, czego chcę. – barsoap

+1

cóż, ten przykład sugeruje, że nie potrzebujesz całej mocy GADT dla twojego 'data Rec', ale wciąż płacisz cenę w kategoriach wnioskowania typu ... więc może jest trochę miejsca na ładną składnię jak GADTs jednocześnie utrzymując wnioskowanie o typie jako dobre zwykłe ADT. – aavogt

Powiązane problemy