Haskell: 约束中的非类型变量参数
Haskell: Non type-variable argument in the constraint
我创建了一些函数来让 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)
一切都很好,直到我想到:"Hey, it would be nice to make that functions (actualy, operators) work with thigs like Line
- not only Point
"
所以我声明了一个 class(为了简单起见,不使用 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)
Point a
数据类型的 Moving
实例:
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 仍然建议我把它包括在内。
如何修复我的 class / 实例以使参数多态性正常工作? :)
And the thing that confuses me much: I put the FlexibleContexts pragma to the pragma listing in the head, but ghcu still suggest me to get it included.
这只会启用模块本身的扩展。要在 GHCi 中编写此代码,您需要在 GHCi 中启用扩展::set -XFlexibleContexts
.
但这只是问题的一部分。看起来你的 class p
应该确定 n
:你只能将 Point a
上下移动 a
,对吗?但就目前而言,没有什么能阻止您定义更多 Moving (Point a) SomeOtherType
个实例,并且编译器不会假设您不会。因此推断类型中的 a
和 n
是完全不相关的,您希望它们相同。这可以通过添加 FunctionalDependencies
extension 并将 class 声明更改为 say
来解决
class Num n => Moving p n | p -> n where
这意味着不能有相同 p
和不同 n
的实例。
我认为这足以让它发挥作用。该代码仍然是不确定的,因为它允许任何数字 a
,但默认规则将选择 Integer
.
我创建了一些函数来让 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)
一切都很好,直到我想到:"Hey, it would be nice to make that functions (actualy, operators) work with thigs like Line
- not only Point
"
所以我声明了一个 class(为了简单起见,不使用 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)
Point a
数据类型的 Moving
实例:
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 仍然建议我把它包括在内。
如何修复我的 class / 实例以使参数多态性正常工作? :)
And the thing that confuses me much: I put the FlexibleContexts pragma to the pragma listing in the head, but ghcu still suggest me to get it included.
这只会启用模块本身的扩展。要在 GHCi 中编写此代码,您需要在 GHCi 中启用扩展::set -XFlexibleContexts
.
但这只是问题的一部分。看起来你的 class p
应该确定 n
:你只能将 Point a
上下移动 a
,对吗?但就目前而言,没有什么能阻止您定义更多 Moving (Point a) SomeOtherType
个实例,并且编译器不会假设您不会。因此推断类型中的 a
和 n
是完全不相关的,您希望它们相同。这可以通过添加 FunctionalDependencies
extension 并将 class 声明更改为 say
class Num n => Moving p n | p -> n where
这意味着不能有相同 p
和不同 n
的实例。
我认为这足以让它发挥作用。该代码仍然是不确定的,因为它允许任何数字 a
,但默认规则将选择 Integer
.