2011-07-10 44 views
13

Ogólne pytanie brzmi, która struktura modułów jest wygodniejsza przy dodawaniu wystąpień dla istniejących obiektów? Jakie są plusy i minusy?Jak organizować moduły Haskella z instancjami: przyklejać do typu danych w porównaniu do typu?

Załóżmy, że chcę dodać instancję NFData dla typu Seq. Mogę umieścić go w:

  • Data.Sequence.Extra (tak samo odbywa się w pakiecie vty)
  • Data.Sequence.Instances.NFData (bardziej precyzyjna)
  • Control.DeepSeq.Instances
  • Control.DeepSeq.Instances.Sequence

To sprawa gdy nie jestem właścicielem ani klasy typów, ani typu danych. Inną często spotykaną sytuacją jest posiadanie klasy typu i chęć dodawania instancji dla typów danych z jakiegoś "ciężkiego" pakietu z Hackage, takiego jak OpenGL. Powiedzmy, że klasa typu I zaprojektowana jest bardzo lekka i nie ma bezpośredniego związku z OpenGL. Nie chcę, aby moja klasa była zależna od "ciężkiego" pakietu, więc chcę umieścić instancje OpenGL w osobnym module (to moje intuicyjne uczucie, jeśli masz inne zdanie, porozmawiajmy o tym). Więc, co to moduł powinien być:

  • MyClass.Instances.OpenGL
  • Graphics.Rendering.OpenGL.Extra (wraz z instancjami dla innych klas)
  • Graphics.Rendering.OpenGL.Instances.MyClass

Co jest bardziej elastyczne rozwiązanie? W pewnym momencie OpenGL można zastąpić inną biblioteką lub można również wymienić MyClass. Czy są jakieś subtelne niuanse?

Ponadto, który system jest lepszy, czy wybrać MyClass.Instances Wariant:

  • MyClass.Class moduł do samej klasy i podstawowych przypadkach i MyClass modułu ponownego eksportu to (a może MyClass.Instances)
  • MyClass modułu dla klasy i podstawowy instancje i MyClass.All reexportuje wszystko moduł
  • MyClass dla klasy i podstawowych instancji oraz brak modułu do ponownego eksportu.
+0

To co robisz nazywa się "instancjami sierocymi" i jest uważane za złe, ponieważ ułatwia definiowanie wielu wystąpień tej samej klasy dla tego samego typu i sprawia, że ​​dobre biblioteki są niekompatybilne ze sobą. Było jeszcze inne pytanie omawiające je szczegółowo: http://stackoverflow.com/questions/3079537/orphaned-instances-in-haskell. – Rotsor

+0

Dla problemu Rotsora - biblioteka "ogólna" nie powinna zajmować się wdrażaniem instancji dla klas/typów danych, których nie definiuje. Dla biblioteki prywatnej lub pliku wykonywalnego/aplikacji jest to w porządku, ale biblioteka publiczna nie powinna tego robić. W przypadku pierwotnego problemu - problem nie polega na tym, gdzie w przestrzeni nazw zdefiniowano instancję, ale że może istnieć więcej niż jedna biblioteka udostępniająca instancję. Najlepszym rozwiązaniem jest prawdopodobnie posiadanie pakietów "instancji" w Hackage, gdzie programiści dostarczają instancje kanoniczne dla klas/typów danych poza Bazą. –

+0

@Rotsor, to dobra uwaga (chociaż nie ma wspólnej opinii na temat komentarza pod linkiem). Czy wynika z tego, że kiedy posiadam klasę typu, zwiążę z nią instancje? – modular

Odpowiedz

12

Zwykle proces decydowania gdzie umieścić instancję idzie mniej więcej tak:

  1. Jeśli robisz nowy typ danych i chcą instancję dla istniejącej klasy:

    Umieść instancję w tym samym module co typ danych.

  2. Jeśli tworzysz nową klasę typów i chcesz tworzyć instancje dla istniejących typów.

    Umieść instancje w tym samym module, co klasa typu.

  3. Zarówno klasa typu, jak i typ danych już istnieją (twój przypadek).

    Jeśli wystąpienie jest wystarczająco ogólne, powinienem skontaktować się z autorem klasy typów lub typu danych i spróbować przekonać ich, aby dodać instancję w swoim pakiecie.

    W przeciwnym razie utwórz opakowanie jednostkowe newtype i napisz do tego wystąpienie.

    Tylko w ostateczności rozważ tworzenie instancji osieroconej.

+0

Zgadzam się ze wszystkim, co powiedziałeś, ale przez większość czasu instancja osierocona jest jedynym możliwym rozwiązaniem. – augustss

+2

Chętnie buduję instancje osierocone w moich plikach wykonywalnych, ale staram się tego unikać dla bibliotek. –

Powiązane problemy