记录选择器和类型无效 类
Invalid record selector and type classes
我有一个 class Movable
和多个实例化这个 class 的数据类型。我想为所有这些 classes 创建一个通用的移动函数,如下所示,但显然我的记录语法不正确,因为我收到以下错误:
src\Controller.hs:24:13: error:
* `position' is not a record selector
* In the expression: o {position = (x', y')}
In an equation for `move':
move o
= o {position = (x', y')}
where
(x, y) = position o
(vx, vy) = velocity o
x' = x + vx
y' = y + vy
|
24 | move o = o {position = (x', y')}
| ^^^^^^^^
我尝试应用此 Whosebug answer,但没有成功。 如何解决这个问题?或者除了使用记录语法之外还有其他方法可以解决这个问题吗?
在这里你可以看到我的代码:
type Position = (Float, Float)
type Velocity = (Float, Float)
class Movable m where
position :: m -> Position
velocity :: m -> Velocity
data Player = Player {
playerBulletType :: Bullet,
playerHealth :: Health,
playerMaxVelocity :: MaxVelocity,
playerVelocity :: Velocity,
playerPosition :: Position,
playerSprite :: Sprite
}
instance Movable Player where
position = playerPosition
velocity = playerVelocity
move :: Movable o => o -> o
move o = o {position = (x', y')}
where (x, y) = position o
(vx, vy) = velocity o
x' = x + vx
y' = y + vy
首先,作为,您可能根本不应该使用任何class来解决这个问题,而只是一个参数化记录。
A class 不像在 OO 中那样,它实际上定义了一个数据结构。它只是定义了一些可能使用实例类型值的操作来给你一些东西,但这只是一个特例。这些值也可能是即时计算的,通常没有办法将它们 设置 为另一个值。如果你需要那个,那么这样的“getter方法”是不够的,你还需要一个“setter”。在现代 Haskell 中惯用地,你会一次性完成:getter 和 setter 的组合称为 lens.
import Control.Lens
class Movable m where
position :: Lens' m Position
velocity :: Lens' m Velocity
instance Movable Player where
position f plyr = fmap (\p -> plyr{playerPosition=p}) . f $ playerPosition plyr
velocity f plyr = fmap (\v -> plyr{playerVelocity=v}) . f $ playerVelocity plyr
那你可以写
move :: Movable o => o -> o
move o = o & position .~ (x', y')
where (x, y) = o ^. position
(vx, vy) = o ^. velocity
x' = x + vx
y' = y + vy
或者,更短的 vector-space,
import Data.AffineSpace
move :: Movable o => o -> o
move o = o & position %~ (.+^ o^.velocity)
我有一个 class Movable
和多个实例化这个 class 的数据类型。我想为所有这些 classes 创建一个通用的移动函数,如下所示,但显然我的记录语法不正确,因为我收到以下错误:
src\Controller.hs:24:13: error:
* `position' is not a record selector
* In the expression: o {position = (x', y')}
In an equation for `move':
move o
= o {position = (x', y')}
where
(x, y) = position o
(vx, vy) = velocity o
x' = x + vx
y' = y + vy
|
24 | move o = o {position = (x', y')}
| ^^^^^^^^
我尝试应用此 Whosebug answer,但没有成功。 如何解决这个问题?或者除了使用记录语法之外还有其他方法可以解决这个问题吗? 在这里你可以看到我的代码:
type Position = (Float, Float)
type Velocity = (Float, Float)
class Movable m where
position :: m -> Position
velocity :: m -> Velocity
data Player = Player {
playerBulletType :: Bullet,
playerHealth :: Health,
playerMaxVelocity :: MaxVelocity,
playerVelocity :: Velocity,
playerPosition :: Position,
playerSprite :: Sprite
}
instance Movable Player where
position = playerPosition
velocity = playerVelocity
move :: Movable o => o -> o
move o = o {position = (x', y')}
where (x, y) = position o
(vx, vy) = velocity o
x' = x + vx
y' = y + vy
首先,作为
A class 不像在 OO 中那样,它实际上定义了一个数据结构。它只是定义了一些可能使用实例类型值的操作来给你一些东西,但这只是一个特例。这些值也可能是即时计算的,通常没有办法将它们 设置 为另一个值。如果你需要那个,那么这样的“getter方法”是不够的,你还需要一个“setter”。在现代 Haskell 中惯用地,你会一次性完成:getter 和 setter 的组合称为 lens.
import Control.Lens
class Movable m where
position :: Lens' m Position
velocity :: Lens' m Velocity
instance Movable Player where
position f plyr = fmap (\p -> plyr{playerPosition=p}) . f $ playerPosition plyr
velocity f plyr = fmap (\v -> plyr{playerVelocity=v}) . f $ playerVelocity plyr
那你可以写
move :: Movable o => o -> o
move o = o & position .~ (x', y')
where (x, y) = o ^. position
(vx, vy) = o ^. velocity
x' = x + vx
y' = y + vy
或者,更短的 vector-space,
import Data.AffineSpace
move :: Movable o => o -> o
move o = o & position %~ (.+^ o^.velocity)