我创建了一些函数来让2D几何体感到舒适。 在此示例中,我使用Geom2D from CubicBezier package。
我的计划的完整代码:https://gist.github.com/nskeip/3784d651ac646a67c5f246f048949af4
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-}
import Geom2D
left :: (Num a) => Point a -> a -> Point a
left (Point x y) n = Point (x - n) y
right :: (Num a) => Point a -> a -> Point a
right (Point x y) n = Point (x + n) y
up :: (Num a) => Point a -> a -> Point a
up (Point x y) n = Point x (y - n)
down :: (Num a) => Point a -> a -> Point a
down (Point x y) n = Point x (y + n)
他们的工作方式如下:
> (Point 0 0) `up` 10
Point 0.0 -10.0
Point
的定义如下:
data Point a = Point {
pointX :: !a,
pointY :: !a
} deriving (Eq, Ord, Functor, Foldable, Traversable)
一切都很好,直到我想:"嘿,让这些函数(实际上,运算符)与Line
之类的问题一起工作会很好 - 不仅Point
&#34 ;
所以我宣布了一个班级(不考虑left
和right
以保持简单):
class Num n => Moving p n where
up' :: n -> p -> p
down' :: n -> p -> p
up' n = down' (-n)
down' n = up' (-n)
Moving
数据类型Point a
的实例:
instance Num a => Moving (Point a) a where
up' n (Point x y) = Point x (y - n)
但是当我尝试使用它时,我收到了一个错误:
✗ ghci ./uno.hs
GHCi, version 7.10.3: http://www.haskell.org/ghc/ :? for help
[1 of 1] Compiling Main ( uno.hs, interpreted )
Ok, modules loaded: Main.
*Main> let p = Point { pointX = 0, pointY = 0 }
*Main> up' 10 p
<interactive>:3:1:
Non type-variable argument in the constraint: Moving (Point a) n
(Use FlexibleContexts to permit this)
When checking that ‘it’ has the inferred type
it :: forall n a. (Num a, Moving (Point a) n) => Point a
让我感到困惑的是:我把FlexibleContexts
pragma放到头部的pragma列表中,但是ghcu仍然建议我把它包含在内。
如何修复我的类/实例以使参数多态性有效? :)
答案 0 :(得分:1)
让我感到困惑的是:我把FlexibleContexts pragma放到头部的pragma列表中,但是ghcu仍然建议我把它包含在内。
这仅启用模块本身的扩展。要在GHCi中编写此代码,您需要在GHCi中启用扩展名::set -XFlexibleContexts
。
但这只是问题的一部分。您的班级p
似乎应该确定n
:您只能Point a
向上和向下移动a
,对吧?但是就目前而言,没有什么能阻止你定义更多的Moving (Point a) SomeOtherType
实例,并且编译器并不认为你不会。因此,推断类型中的a
和n
完全不相关,您希望它们相同。这可以通过添加FunctionalDependencies
extension并将类声明更改为
class Num n => Moving p n | p -> n where
这意味着不能存在具有相同p
和不同n
的实例。
我认为这足以让它发挥作用。代码仍然不确定,因为它允许任何数字a
,但默认规则将选择Integer
。