2012-04-02 18 views
7

Podstawową ideą jest to, że mam szereg funkcji, które działają na każdym typie z konkretnej klasy, ale w czasie wykonywania program powinien odczytać plik konfiguracyjny i wyodrębnić element jednego typów w klasie.Przezroczyste wdrażanie określonej formy dynamicznego pisania

Na przykład, mam klasę "Współczynnik", różne jej przykłady i funkcje różnych typów, które są polimorficzne w stosunku do typów tej klasy; w czasie wykonywania jeden określony typ tej klasy ma zostać określony i przekazany.


Nie jestem pewien, jak poprawnie rozwiązać ten problem; Próbowałem tworzących typy „związku”, robi coś takiego:

data CompoundCoeff = CompoundInt Int | CompoundDouble Double | ... 

gdzie Int, Podwójne, ... są instancje klasy „współczynnik”.
Jednak zaczął się duży wysiłek, aby dostosować wszystkie funkcje związane z kodem do pracy z tymi złożonymi typami (i to też nie jest dobre rozwiązanie). Byłoby OK, gdyby wszystkie funkcje miały ten sam, łatwy typ, np.

Coefficient a => a -> (stuff not involving a anymore) 

, ale niestety tak nie jest.

Kolejną kwestią wpadłem na to, że używam rodziny typu i mieć coś takiego

class (Monoid (ColourData c), Coordinate (InputData c)) => ColourScheme c where 
    type ColourData c :: * 
    type InputData c :: * 
    colouriseData  :: c -> (ColourData c) -> AlphaColour Double 
    processInput  :: c -> InputData c -> ColourData c 

to nie przechodzi gładko, jeśli będę musiał użyć jakiegoś związku ColourData typu danych, jak Poprzedni; w szczególności nie mogę już zagwarantować, że strumień danych daje spójny typ (a nie tylko różne "podtypy" typu złożonego), i (między innymi) musiałby utworzyć fałszywą instancję Monoid, jeślibym skomponował złożony typ ColourData.

Zajrzałem również do Data.Dynamic, ale znowu nie widzę, jak to właściwie rozwiązać problemy; dokładnie te same problemy wydają się pojawiać (no, trochę gorsze nawet, biorąc pod uwagę, że istnieje tylko jeden "rodzajowy" typ dynamiczny, jak go rozumiem).


Pytanie: W jaki sposób można zaimplementować dynamicznych typów danych podległe poszczególnych klas, bez konieczności przepisywania wszystkie funkcje obejmujące te typy danych? Byłoby najlepiej, gdybym nie musiał poświęcać żadnego rodzaju bezpieczeństwa, ale nie jestem zbyt optymistyczny.
Program powinien odczytać plik konfiguracyjny w czasie wykonywania, a wszystkie wymagane funkcje, polimorficzne względem odpowiedniej klasy, mają być zastosowane.

Odpowiedz

7

Tradycyjny sposób, aby zapewnić obiekt, który gwarantuje, że jest to instancja typeclass Foo, ale nie udziela żadnych dodatkowych gwarancji, jest tak:

{-# LANGUAGE ExistentialTypes #-} 
data SomeFoo = forall a . Foo a => SomeFoo a 

instance Foo SomeFoo where 
    -- all operations just unwrap the SomeFoo straightforwardly 

lub z GADTs, które mogą być bardziej czytelne. ..

data SomeFoo where 
    SomeFoo :: Foo a => a -> SomeFoo 
6

Jedną z propozycji byłoby napisać jedną funkcję najwyższego poziomu, że nie wszystkie wykończenia po wybraniu typu:

topLevel :: SomeTypeClass a => a -> IO() 

Twój program może być napisany tak:

main = do 
    config <- readConfig 
    case config of 
     UseDouble n -> topLevel n 
     UseSymbolic x -> topLevel x 
     UseWidgetFrobnosticator wf -> topLevel wf