2017-10-09 15 views
6

de döngüsünden karşılıklı özyinelemeli varsayılan yöntemleri önleme Şu anda aşağıdaki gibi bir yapıya var:zamanında

class F a where 
    f :: ... 
    default f :: (G a...) => ... 
    f = (some definition in terms of g) 

class F a => G a where 
    g :: ... 
    default g :: (C a...) => ... 
    g = (some definition in terms of f) 

umarım biraz düz İngilizce, hep g açısından f yazabilir. a bazen kısıtını karşıladığında bazen f olarak yazabilirim. Birisi yazıyor, bir tür TC T

instance F T 
instance G T 

Bu çalışma zamanında derlemek ve döngü olacak tatmin söylersem

Burada bkz konudur. Her iki varsayılan tanım doğru olsa da, en az birinin tanımlanması önemlidir.

f ve g aynı sınıftaysa, bunu MINIMAL pragma ile çözebilirim, ancak bu durumda değiller.

da aynı sınıfta f ve g konularak g her tanımı için f bir tanımı yoktur ederken gibi, mümkün görünmemektedir, f her tanımı için g bir tanım yoktur. Bir olasılık,, F'a taşınıyor ama aynı zamanda bir C a kısıtlaması getiriyor, ancak a içiniçin uygun olmayan bir tanımlamayla, g tanımlamamı engellerdi.

Karşılaştığım bu ikilemi çözmek için bunu yeniden düzenlemek için herhangi bir yol var mı?

+1

Başka çare seçenek g' ve/veya 'f'' varsayılan tanımı var, ancak bunun yerine örnek-yazarlar için * açıkça * opt-in için kullanabileceği tek başına bir işlevi vermemeyi olurdu "varsayılan" uygulama ('g = defaultG' yazarak). İnşallah en azından bir tanesi kasıtlı olarak * biraz daha zorlaştırın * her ikisi de varsayılan olarak bırakın, çünkü en azından bir tanesi kasıtlı bir seçimdi. – Ben

cevap

0

Önceki cevabım saçmalıktı, bu yüzden burada (umarız) daha iyi bir tane var. Bu en azından derleme zamanında bir uyarı verecektir. Her ikisi de a hem hem de G için örneklere sahipseveya g sınıflarını G sınıfında uygulamaktır, ancak G örneğinde yalnızca imkansızdır.

{-# LANGUAGE DefaultSignatures #-} 

class C a where 

class F a where 
    f :: a -> a 
    default f :: (G a) => a -> a 
    f = g 

class F a => G a where 
    {-# MINIMAL (f'|g) #-} 

    f' :: a -> a 
    f' = f 

    g :: a -> a 
    default g :: (C a) => a -> a 
    g = f' 

instance F Integer where 
    f = succ 

instance F Int 
instance G Int where 
    g = succ 

instance C Float 
instance F Float 
instance G Float where 
    f' = succ 

-- This will give a compile time warning, but will still 
-- loop at runtime: 
instance C Double 
instance F Double 
instance G Double