2010-10-23 14 views
6

Piszę grę w węża w Haskell. Są to tylko niektóre z rzeczy mam:Jak mały powinienem tworzyć moduły w Haskell?

  • typ Coord dane
  • typ Line dane
  • typ Rect dane
  • Klasa Polygon typ, który pozwala mi uzyskać Rect postaci seria linii ([Line]).
  • Klasa typu Impassable, która pozwala mi uzyskać Line jako serię szkieletów ([Coord]), dzięki czemu mogę wykryć kolizje między innymi Impassable s.
  • Klasa typu Draw dla wszystkiego, co chcę narysować na ekranie (HSCurses).
  • Wreszcie używam QuickCheck, więc chcę zadeklarować instancje Arbitrary dla wielu z tych rzeczy.

Obecnie mam wiele z nich w osobnych modułach, więc mam dużo małych modułów. Zauważyłem, że muszę je zaimportować dla siebie, więc zastanawiam się, o co chodzi.

Jestem szczególnie zdezorientowany instancjami Arbitrary. Podczas korzystania z -Wall pojawia się ostrzeżenie o osieroconych instancjach, gdy ja, ale te wystąpienia razem w jednym pliku testowym, rozumiem, że mogę uniknąć tego ostrzeżenia, umieszczając te wystąpienia w tym samym module, co typ danych, ale wtedy będę potrzebować do import Test.QuickCheck dla wszystkich modułów, które wydają się głupie, ponieważ funkcja QuickCheck powinna być wymagana tylko podczas budowania pliku wykonywalnego testu.

Wszelkie porady dotyczące konkretnego problemu z QuickCheck byłyby mile widziane, podobnie jak wskazówki dotyczące bardziej ogólnego problemu, jak/gdzie programy powinny być podzielone na moduły.

Odpowiedz

1

Generalnie kładę większy nacisk na interfejs modułu zdefiniowany przez funkcje, które on eksponuje, a nie na typy danych, które eksponuje. Czy niektóre typy mają wspólny zestaw funkcji? Potem umieściłbym je w tym samym module.

Ale moja praktyka prawdopodobnie nie jest najlepsza, ponieważ zazwyczaj piszę małe programy. Radziłbym spojrzeć na jakiś kod z Hackage, aby zobaczyć, co robią opiekunowie pakietów.

Jeśli istnieje sposób sortowania pakietów według oceny społeczności lub liczby pobrań, byłoby to dobre miejsce do rozpoczęcia. (Myślałem, że tak było, ale teraz, gdy go szukam, nie mogę go znaleźć.) W przeciwnym razie spójrz na pakiety, których już używasz.

+0

Istnieją linki do rankingu według liczby pobrań i liczby odwrotnych zależności tutaj: http://stackoverflow.com/questions/3663550/which-haskell-package-for-json/3663601#3663601 –

4

Możesz zjeść swoje ciasto i je zjeść. Możesz ponownie wyeksportować moduły.

module Geometry 
    (module Coord, module Line, module Rect, module Polygon, module Impassable) 
where 

Zwykle używam modułu za każdym razem, gdy mam pełną abstrakcję - tj. Gdy znaczenie typu danych różni się od jego implementacji. Mając małą wiedzę na temat twojego kodu, prawdopodobnie zgrupowałbym razem Polygon i Impassable, prawdopodobnie tworząc typ danych Collision, aby reprezentować to, co zwracają. Ale Coord, Line i Rect wydają się dobrymi abstrakcjami i prawdopodobnie zasługują na własne moduły.

+0

Wszelkie sugestie co zrobić o problemie QuickCheck? –

+1

To jest trudny problem, nad którym pracowałem. Myślę, że teraz najlepszym wyjściem jest poradzenie sobie z sierotami, jak sugeruje John. Myślę, że właściwą metodą jest "syndykatory dystrybucji", więc zamiast "instance Arbitrary Coord" masz funkcję 'arbitraryCoord :: Distribution Coord'. Używanie go w testach jest nieco bardziej uciążliwe, ale jest bardziej elastyczne i modułowe, ponieważ możesz mieć wiele dystrybucji tego samego typu (w szczególności, jeśli zdefiniowane są dwie różne dystrybucje, świat nie eksploduje). – luqui

2

Do celów testowych używam oddzielnych modułów dla instancji Arbitrary. Chociaż generalnie unikam sierocych instancji, moduły te są budowane tylko podczas budowania pliku wykonywalnego testu, więc nie mam nic przeciwko sierotom lub że nie są one czyste. Możesz także użyć -fno-warn-orphans, aby wyłączyć tylko ten komunikat ostrzegawczy.

+0

Masz osobny moduł dla _all_ instancji 'Arbitrary'? –

+0

@Ollie Saunders - zależy to od wielkości projektu. W przypadku mniejszych projektów używam dwóch modułów do testowania: jeden ma instancje 'Arbitrary' i inny dodatkowy kod, jeśli jest to konieczne, a drugi moduł ma właściwości QuickCheck. W przypadku większych projektów podoba mi się układ używany w ramach Snap. Mają moduł testowy dla każdego zwykłego modułu, który zawiera arbitralne instancje i testy właściwości. –

0

Jednym z rozwiązań QuickCheck jest użycie preprocesora C do selektywnego włączania instancji Arbitrali podczas testowania. Umieszczasz instancje Arbitracyjne bezpośrednio w swoich głównych modułach, ale zawijacie je makrami preprocesora, a następnie umieszczacie flagę "testową" w pliku Cabal.