Використання класів типу Haskell для забезпечення комутативності


11

Я хочу визначити клас типу для геометричних об'єктів, які можна перетинати між собою:

class Intersect a b c | a b -> c where
  intersect :: a -> b -> c
-- Language extensions: -XMultiParamTypeClasses, -XFunctionalDependencies

Ідея полягає у тому, щоб мати функції перетину загального призначення, які можуть обробляти об'єкти різних типів. Можна було б уявити такі випадки, як

instance Intersect Line Plane (Maybe Point) where
  ...
instance Intersect Plane Plane (Maybe Line) where
  ...

Але я також хочу заявити, що перетин є комутативним:

instance (Intersect a b c) => Intersect b a c where
  intersect x y = intersect y x
-- Language extensions: -XUndecidableInstances

Проблема полягає в тому, що щоразу, коли я оцінюю, intersect x yне визначаючи попередньо екземпляр форми Intersect a b c, де aє тип xі bє тип y, програма переходить у нескінченний цикл , імовірно, викликаний рекурсивною заявою екземпляра про комутативність. В ідеалі я хочу, щоб щось на зразок intersect Egg Baconне вдалося перевірити тип, тому що жоден такий екземпляр не був визначений, не вловлюйте мене у нескінченному циклі. Як я можу це здійснити?


Здається, щось, що ви можете спробувати зробити, використовуючи сімейства типів. Ви можете отримати кращу відповідь на переповнення стека.
Бенджамін Ходжсон

2
Ось допис у блозі про монаду, яка нав'язує комунікативність
Даніель Діас Каріт

Відповіді:


2

По-перше, ви можете використовувати комутативний пакет, і в цьому випадку ви зміните підпис типу intersectдо наступного, але в іншому випадку решта вашого коду буде "просто працювати":

instersect :: Commutative a b -> c

Однак ви також можете використовувати QuickCheck з hspec для того, щоб запустити тест властивості на всіх примірниках вашого typeclass, щоб переконатися, що він фактично змінюється. Це може зменшити накладні витрати - вам доведеться робити орієнтир, оскільки я не знаю, що знаходиться в верхній частині голови. Наприклад:

import Test.Hspec

main :: IO ()
main = hspec $ do
    describe "intersect" $ do
        parallel $ it "should commute" $ do
            property $ \x y -> intersect x y == intersect (y :: Point) (x :: Line)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.