2016-02-03 46 views
8

Czy jest jakiś powód, dlaczego ten kod nie jest kompilowany:Dlaczego kompilator nie mógł dopasować typu "a == a" z "True" dla rodziny typów?

type family Foo a b :: Bool where 
    Foo a b = a == b 

foo :: Foo a b ~ True => Proxy a -> Proxy b 
foo _ = Proxy 

bar :: Proxy a -> Proxy a 
bar = foo 

z błędem:

Couldn't match type ‘a == a’ with ‘'True’ 
Expected type: 'True 
    Actual type: Foo a a 

ale jeśli mogę zmienić definicję rodziny typ do

type family Foo a b :: Bool where 
    Foo a a = True 
    Foo a b = False 

jest kompilowany dobrze?

(ghc-7.10.3)

+5

Gdzie jest zdefiniowana rodzina typów "=="? Czy jest automatycznie usuwany z instancji przez GHC? Jeśli tak, GHC musi liczyć się z możliwością dziwnego przypadku, w którym na jakiś niestandardowy typ '(==) = \ _ _ -> False', tak myślę. – chi

+1

Czy możesz podać pełny przykład działania? Kiedy próbuję twojego przykładu, dostaję różne błędy niż ten, który pokazałeś. –

+2

@chi, lub nie dziwne: '(niech x = 0/0 na x == x) ~> Fałsz. – user3237465

Odpowiedz

9

W związku z prośbą o całkowitym przykład roboczego od Daniel Wagner, znalazłem odpowiedź.

Kompletny przykład najpierw:

{-# LANGUAGE TypeFamilies #-} 
{-# LANGUAGE TypeOperators #-} 
{-# LANGUAGE DataKinds #-} 
{-# LANGUAGE UndecidableInstances #-} 
{-# LANGUAGE PolyKinds #-} 
module Test where 

import Data.Type.Equality(type (==)) 
import Data.Proxy(Proxy(..)) 

type family Foo a b :: Bool where 
    Foo a b = a == b 

foo :: Foo a b ~ True => Proxy a -> Proxy b 
foo _ = Proxy 

bar :: Proxy a -> Proxy a 
bar = foo 

Problemem tutaj jest z PolyKinds Pragma. Bez niego działa dobrze. I prawdopodobnie trzeba go tak, że mogę napisać

bar :: Proxy (a :: *) -> Proxy a 

i wszystko idzie dobrze.

Powód jest teraz jasny. Rodzina typów (==) nie ma instancji typu poly-kinded (szczegóły wyjaśniające, dlaczego takie przykłady nie zostały dostarczone here), więc nie możemy zmniejszyć wszystkich równości. Musimy więc określić rodzaj.

+0

@haoformayor Podczas cytowania treści ze źródeł zewnętrznych powinieneś używać blockquotes, aby było jasne, co zostało cytowane. W tym konkretnym przypadku formatowanie było straszne i wymagałoby pewnego traktowania. Również edytowana zawartość * nie * jest niezbędna do udzielenia odpowiedzi na to pytanie i nie ma potrzeby jej kopiowania. Odpowiedź jest już kompletna bez niej, "odpowiedź" na pytanie, na które nie ma polikinezowanej instancji, można udzielić w innym pytaniu lub pozostawić jako link do * dalszego * czytania. – Bakuriu

+0

Jaka jest użyteczność twojej rodziny typu "=="? Zwykle znacznie łatwiej jest pracować z rodzimą równością ('~') niż z budową równości Boole'a w systemie typu. Pod koniec dnia musisz użyć '~', aby cokolwiek zrobić z wynikiem '==', tak jak w 'foo'. –

+0

@BenjaminHodgson: '==' nie jest moje. Jest z pakietu 'base'. Jest to rodzina typu, której wynik ma rodzaj 'Bool'. Z drugiej strony, wynik '~' ma rodzaj "ograniczenia". Zatem '==' jest możliwe do wykorzystania w obliczeniach typu boolowskiego. Zamiast tego nie można użyć '~'. –