Usando classes do tipo Haskell para impor a comutatividade

11

Eu quero definir uma classe de tipo para objetos geométricos que podem ser cruzados:

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

A idéia é ter funções de interseção de uso geral que possam manipular objetos de tipos diferentes. Pode-se imaginar casos como

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

Mas também quero declarar que a interseção é comutativa:

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

O problema é que sempre que eu avalio intersect x ysem definir primeiro uma instância do formulário Intersect a b c, onde aé o tipo xe bo tipo de y, o programa entra em um loop infinito , provavelmente causado por uma declaração de instância recursiva sobre a comutatividade. Idealmente, quero que algo pareça intersect Egg Baconfalhar na verificação de tipo porque nenhuma instância foi definida, não me prenda em um loop infinito. Como posso implementar isso?

Herng Yi
fonte
Parece algo que você poderia tentar fazer usando famílias de tipos. Você pode obter uma resposta melhor no estouro de pilha.
Benjamin Hodgson
2
Aqui está um post sobre uma mônada que impõe a comutatividade, talvez ele possa ajudar: gelisam.blogspot.ca/2013/07/the-commutative-monad.html
Daniel Díaz Carrete

Respostas:

2

Primeiro, você pode usar o pacote comutativo ; nesse caso, você modificaria a assinatura de tipo intersectpara o seguinte, mas, caso contrário, o restante do seu código "funcionaria":

instersect :: Commutative a b -> c

No entanto, você também pode usar o QuickCheck com hspec para executar um teste de propriedade em todas as instâncias da sua classe de tipo para garantir que ele efetivamente seja comutado. Isso pode reduzir a sobrecarga - você teria que fazer uma referência, pois eu não sei de nada. Por exemplo:

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)

fonte