使用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是的类型xb是的类型)y程序都会进入无限循环,这大概是由有关可交换性的递归实例声明引起的。理想情况下,我希望intersect Egg Bacon无法进行类型检查,因为没有定义此类实例,而不是使我陷入无限循环。我该如何实施?


听起来像您可以尝试使用类型家族来做的事情。您可能会在堆栈溢出时得到更好的响应。
本杰明·霍奇森

2
这是有关强制执行可交换性的monad的博客文章,也许可以提供帮助:gelisam.blogspot.ca/2013/07/the-commutative-monad.html
DanielDíazCarrete 2015年

Answers:


2

首先,可以使用交换包,在这种情况下,您可以将的类型签名修改intersect为以下内容,否则,其余代码将“正常工作”:

instersect :: Commutative a b -> c

但是,您还可以将QuickCheck与hspec结合使用,以便对类型类的所有实例运行属性测试,以确保它确实可以上下班。这可能会减少管理费用-您必须做一个基准测试,因为我不清楚。例如:

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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.