Menggunakan kelas tipe Haskell untuk menegakkan komutatif


11

Saya ingin mendefinisikan kelas tipe untuk objek geometris yang dapat disatukan:

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

Idenya adalah memiliki fungsi persimpangan tujuan umum yang dapat menangani objek dari berbagai jenis. Orang bisa membayangkan contoh seperti itu

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

Tetapi saya juga ingin menyatakan bahwa persimpangan adalah komutatif:

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

Masalahnya adalah bahwa setiap kali saya mengevaluasi intersect x ytanpa terlebih dahulu mendefinisikan instance dari form Intersect a b c, di mana aadalah tipe xdan btipe y, program masuk ke loop tak terbatas , mungkin disebabkan oleh deklarasi instance rekursif tentang komutativitas. Idealnya saya ingin sesuatu seperti intersect Egg Bacongagal mengetik-periksa karena tidak ada contoh seperti itu didefinisikan, tidak menjebak saya dalam loop yang tak terbatas. Bagaimana saya bisa menerapkan ini?


Kedengarannya seperti sesuatu yang bisa Anda coba lakukan menggunakan keluarga tipe. Anda mungkin mendapatkan respons yang lebih baik pada stack overflow.
Benjamin Hodgson

2
Berikut adalah posting blog tentang monad yang memberlakukan commutativity, mungkin dapat membantu: gelisam.blogspot.ca/2013/07/the-commutative-monad.html
Daniel Díaz Carrete

Jawaban:


2

Pertama, Anda bisa menggunakan paket komutatif , dalam hal ini Anda akan memodifikasi tipe tanda tangan intersectuntuk yang berikut ini, tetapi jika tidak, sisa kode Anda akan "berfungsi":

instersect :: Commutative a b -> c

Namun, Anda juga dapat menggunakan QuickCheck dengan hspec untuk menjalankan tes properti di semua instance dari typeclass Anda untuk memastikan bahwa itu sebenarnya bolak-balik. Ini dapat mengurangi overhead - Anda harus melakukan benchmark karena saya tidak tahu dari atas kepala saya. Misalnya:

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)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.