Utilizzo delle classi di tipi Haskell per applicare la commutatività


11

Voglio definire una classe di tipi per oggetti geometrici che possono essere intersecati insieme:

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

L'idea è quella di disporre di funzioni di intersezione generiche in grado di gestire oggetti di diverso tipo. Si potrebbero immaginare casi come

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

Ma voglio anche dichiarare che l'intersezione è commutativa:

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

Il problema è che ogni volta che valuto intersect x ysenza prima definire un'istanza del modulo Intersect a b c, dove aè il tipo xe bil tipo di y, il programma passa in un ciclo infinito , presumibilmente causato dalla dichiarazione ricorsiva dell'istanza sulla commutatività. Idealmente, vorrei che qualcosa del genere intersect Egg Baconnon riuscisse a controllare il tipo perché non era stata definita un'istanza del genere, non mi intercettava in un ciclo infinito. Come posso implementarlo?


Sembra qualcosa che potresti provare a fare usando le famiglie di tipi. Potresti ottenere una risposta migliore sull'overflow dello stack.
Benjamin Hodgson,

2
Ecco un post sul blog su una monade che impone la commutatività, forse può aiutare: gelisam.blogspot.ca/2013/07/the-commutative-monad.html
Daniel Díaz Carrete,

Risposte:


2

Innanzitutto, è possibile utilizzare il pacchetto commutativo , nel qual caso si modifica la firma del tipo intersectin quanto segue, ma altrimenti il ​​resto del codice "funzionerebbe":

instersect :: Commutative a b -> c

Tuttavia, puoi anche utilizzare QuickCheck con hspec al fine di eseguire un test di proprietà su tutte le istanze della tua tabella dei tipi per garantire che sia effettivamente commutato. Ciò può ridurre le spese generali: dovresti fare un benchmark poiché non so bene. Per esempio:

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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.