2012-03-21 10 views
8

O ile wiem, nie sądzę, że mogłoby to spowodować jakąkolwiek różnicę, że id1 i id2 pochodzą z klasy typów, a id1 i id2 nie. Używam "ghc Rewrite" z najnowszą platformą Haskell (zarówno w wersji GHC 7.0.4, jak i teraz w wersji 7.4.1), i spodziewam się, że to1 również wystrzeli.Reguły przepisywania niepoprawne w przypadku reguł pasujących do wielu metod instancji

$ ghc Rewrite 
[1 of 1] Compiling RewriteProblems (Rewrite.hs, Rewrite.o) 
Rule fired: rewrite/ez' 
Rule fired: rewrite/to1' 
Rule fired: rewrite/ez 
Rule fired: rewrite/ez 
Rule fired: Class op id2 
Rule fired: Class op id2 

przykład:

{-# OPTIONS_GHC -O -ddump-rule-firings #-} 
module RewriteProblems where 

{-# RULES 
"rewrite/ez" forall a. id1 a = RDUnit 
"rewrite/to1" forall a. id2 (id2 a) = id1 a 
"rewrite/ez'" forall a. id1' a = RDUnit 
"rewrite/to1'" forall a. id2' (id2' a) = id1 a 
    #-} 

class Ider a where 
    id1 :: a -> a 
    id2 :: a -> a 

data RewriteD = RDUnit 

instance Ider RewriteD where 
    {-# INLINE[1] id1 #-} 
    {-# INLINE[1] id2 #-} 
    id1 a = RDUnit 
    id2 a = RDUnit 

testThing1 :: RewriteD 
testThing1 = id1 RDUnit 

testThing2 :: RewriteD 
testThing2 = id2 (id2 RDUnit) 

testThing1' :: RewriteD 
testThing1' = id1' RDUnit 

testThing2' :: RewriteD 
testThing2' = id2' (id2' RDUnit) 

{-# INLINE[1] id1' #-} 
{-# INLINE[1] id2' #-} 
id1' :: RewriteD -> RewriteD 
id2' :: RewriteD -> RewriteD 
id1' a = RDUnit 
id2' a = RDUnit 

Odpowiedz

5

(kilka modyfikacje wprowadzone w całym poście z aktualnych informacji)

W swoim wyjściu, zwróć uwagę na linie Rule fired: Class op id2. Są to reguły automatycznie tworzone przez GHC dla instancji klasy typów. Ta zasada jest pierwsza, więc twoja własna reguła nigdy nie ma szansy na dopasowanie. Jeśli kompilujesz z "-ddump-simpl-iterations", możesz sprawdzić, czy reguła klasy op uruchomi się w pierwszej fazie, po której twoja reguła "to1" nigdy nie będzie pasować.

Oto trochę obejścia. Najpierw skomentuj testThing1, testThing1' i testThing2', aby skompilować tylko testThing2. Jest to jedyna funkcja, w której można przepisać "przepisać/na 1", więc izoluje testowany przypadek, na który patrzysz. Następnie dodać kolejną regułę w postaci:

"rewrite/to_id2'" forall a. id2 a = id2' a 

i zobaczysz wyjście:

$ ghc -c foo.hs 
Rule fired: rewrite/to_id2' 
Rule fired: rewrite/to_id2' 
Rule fired: rewrite/to1' 
Rule fired: rewrite/ez 

Nowa reguła jest teraz wypalania zamiast op klasy, co pozwala rewrite/to1' uproszczenie wyrażenia. Co ciekawe, nie ma znaczenia, czy nowa reguła pojawi się powyżej czy poniżej rewrite/to1 w liście ZASAD.

Nie wiem, dlaczego twoja reguła id2 (id2 a) nie pasuje, a robi to id2 a. Wygląda na to, że powinien się dopasować (zgodnie z -dverbose-core2core), ale tak nie jest. Nadal podejrzewam, że jakiś błąd związany z GHC jakiegoś typu, chociaż widzę to samo zachowanie z ghc-7.4.1, więc nie jest to 4397.

+1

Właśnie zainstalowałem najnowszą wersję GHC - w wersji 7.4.1 i otrzymuję to samo teraz, co poprzednio. Również, tak, zdaję sobie sprawę, że te zasady nie mają znaczenia dla wyników - właśnie zrobiłem ten test, aby wyizolować problem, który dostałem w znacznie bardziej skomplikowanym przykładzie. Wierzę również, że pierwszeństwo właściwie działa tutaj ... po prostu patrząc na wynik naprawdę wygląda na to, że wszystkie moje reguły są podejmowane zanim pojawią się te. – Akh

+0

Jak dokładnie określasz, że twoje reguły są podejmowane? Nie wiem, w jaki sposób GHC może pokazywać reguły, które nie są stosowane, lub która reguła jest używana w przypadku wielu dopasowań. Najlepsze, co możesz zrobić, to sprawdzić, co faktycznie zostało wyrzucone, co jest w tym przypadku regułą klasy op. –

+0

Jeśli zmienisz program, aby metoda instancji zwróciła coś podobnego do błędu, czyli coś innego niż 'RDUnit', na które powinna Cię opuścić reguła przepisywania, optymalizator pozostawia ci wartość błędu w przykładzie' testThing2'. Myślę, że ten przykładowy program był po prostu zbyt daleko posunięty, aby jak najbardziej jasno pokazać problem. – Anthony

Powiązane problemy