2013-08-08 19 views
7

Pracuję z językami osadzonymi w Haskell. Moje języki można wydrukować jako kod źródłowy, dlatego utworzyłem klasę Compile i stworzyłem instancję klasy dla każdego elementu programu, który można wydrukować. W ten sposób mogłem skomponować mój kod. To działało dobrze zanim rozważano koncepcje trybów.Haskell: Nielegalna aplikacja rodziny synonimów w instancji

Każdy język może być używany w dwóch trybach (zaimplementowanych jako instancje klasy Mode). W trybie prostym wszystko jest normalne. W nazwanym trybie wiele elementów programu można zastąpić ciągami. (Działa jak definicje makr.)

Chcę zachować wszystkie reprezentacje jako bezpieczne. Zatem nie można mieszać elementów programowych różnych języków lub różnych trybów.

Problem polega na tym, jak zrzucić języki bez względu na tryb?

{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances #-} 
class Compile a where 
    comp :: a -> String 

-- common elements in all languages 
data ElemA l m = ElemA (ElemB l m) 
data ElemB l m = ElemB 

class Lang l where 
    -- language-specific elements 
    data Instructions l :: * -> * 

-- common modes for all languages 
class Mode l m where 
    type MElemA l m :: * 
    type MElemB l m :: * 

-- mode with normal program elements 
data SimpleMode 
instance Mode l SimpleMode where 
    type MElemA l SimpleMode = ElemA l SimpleMode 
    type MElemB l SimpleMode = ElemB l SimpleMode 

-- a mode where each program element can be replaced with a string 
data NamedMode 
instance Mode l NamedMode where 
    type MElemA l NamedMode = Either String (ElemA l NamedMode) 
    type MElemB l NamedMode = Either String (ElemB l NamedMode) 

-- definition of Lang1 language 
data Lang1 
instance Lang Lang1 where 
    data Instructions Lang1 m 
    = Add (MElemA Lang1 m) (MElemA Lang1 m) (MElemA Lang1 m) 
    | Mul (MElemA Lang1 m) (MElemA Lang1 m) (MElemA Lang1 m) 
    -- | ... 

-- dumping the source code of Lang1 langauge 

-- ILLEGAL TYPE SYNONYM FAMILY APPLICATION HERE 
instance Compile (MElemA Lang1 m) where 
    comp _ = "A" 
-- AND HERE 
instance Compile (MElemB Lang1 m) where 
    comp _ = "B" 

Wiem, że rodziny synonimów typu nie działają dobrze z klasami, więc szukam innego rozwiązania.

Możliwe rozwiązania Jestem świadomy (ale nie chcą używać):

  • Używaj wielu funkcji zamiast pojedynczego polimorficzny comp funkcja.
  • Używaj tylko NamedMode reprezentacji

Odpowiedz

3

Jeden z moich przyjaciół, Zoltán Kelemen wysłał mi rozwiązanie. Używał klas zawijania do enkapsulacji elementu programu określonego języka. W ten sposób wyeliminował aplikacje z rodziny rodzinnej z głowic instancji bez większego wysiłku niż to konieczne.

Poszukuję również innych rozwiązań.

{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-} 
class Compile a where 
    comp :: a -> String 

-- common elements in all languages 
data ElemA l m = ElemA (ElemB l m) 
data ElemB l m = ElemB 

class Lang l where 
    -- language-specific elements 
    data Instructions l :: * -> * 

-- wrapper classes for program elements of Lang1 
data Lang1A m = WrapperA (ElemA Lang1 m) 
data Lang1B m = WrapperB (ElemB Lang1 m) 

-- common modes for all languages 
class Mode l m where 
    type MElemA l m :: * 
    type MElemB l m :: * 

-- mode with normal program elements 
data SimpleMode 
instance Mode l SimpleMode where 
    type MElemA l SimpleMode = ElemA l SimpleMode 
    type MElemB l SimpleMode = ElemB l SimpleMode 

-- a mode where each program element can be replaced with a string 
data NamedMode 
instance Mode l NamedMode where 
    type MElemA l NamedMode = Either String (ElemA l NamedMode) 
    type MElemB l NamedMode = Either String (ElemB l NamedMode) 

-- definition of Lang1 language 
data Lang1 
instance Lang Lang1 where 
    data Instructions Lang1 m 
    = Add (MElemA Lang1 m) (MElemA Lang1 m) (MElemA Lang1 m) 
    | Mul (MElemA Lang1 m) (MElemA Lang1 m) (MElemA Lang1 m) 
    -- | ... 

-- dumping the source code of Lang1 langauge 

-- ILLEGAL TYPE SYNONYM FAMILY APPLICATION HERE 
instance Compile (Lang1A m) where 
    comp (WrapperA e) = "A" 
-- AND HERE 
instance Compile (Lang1B m) where 
    comp (WrapperB e) = "B" 
+0

Również dzięki za wspomnieć podobieństwa z tym inne pytanie: http://stackoverflow.com/questions/2590495/problem-when-mixing-type-classes-and-type-families?rq=1 –

+0

Could zastosowali nowy typ zamiast danych - nie? – lynnard

Powiązane problemy