Chcę zdefiniować klasę typów dla obiektów geometrycznych, które można przecinać razem:
class Intersect a b c | a b -> c where
intersect :: a -> b -> c
-- Language extensions: -XMultiParamTypeClasses, -XFunctionalDependencies
Chodzi o to, aby mieć funkcje przecięcia ogólnego przeznaczenia, które mogą obsługiwać obiekty różnych typów. Można sobie wyobrazić takie przypadki jak
instance Intersect Line Plane (Maybe Point) where
...
instance Intersect Plane Plane (Maybe Line) where
...
Ale chcę również zadeklarować, że skrzyżowanie jest przemienne:
instance (Intersect a b c) => Intersect b a c where
intersect x y = intersect y x
-- Language extensions: -XUndecidableInstances
Problem polega na tym, że ilekroć oceniam intersect x y
bez uprzedniego zdefiniowania wystąpienia formy Intersect a b c
, gdzie a
jest typ x
i b
jest typ y
, program przechodzi w nieskończoną pętlę , prawdopodobnie spowodowaną deklaracją instancji rekurencyjnej o komutatywności. Idealnie intersect Egg Bacon
byłoby, gdyby coś takiego nie sprawdziło się podczas sprawdzania typu, ponieważ nie zdefiniowano takiej instancji, aby nie uwięzić mnie w nieskończonej pętli. Jak mogę to zaimplementować?
źródło
Odpowiedzi:
Po pierwsze, możesz użyć pakietu przemiennego , w którym to przypadku zmodyfikujesz podpis typu
intersect
do następującego, ale w przeciwnym razie reszta kodu „po prostu zadziała”:Jednak możesz także użyć QuickCheck z hspec, aby uruchomić test właściwości we wszystkich instancjach twojej klasy, aby upewnić się, że faktycznie dojeżdża do pracy. Może to zmniejszyć koszty ogólne - musisz zrobić punkt odniesienia, ponieważ nie wiem od samego początku. Na przykład:
źródło