Неверный селектор записей и типы классов - PullRequest
0 голосов
/ 20 октября 2018

У меня есть класс Movable и несколько типов данных, которые создают этот класс.Я хочу создать универсальную функцию перемещения для всех этих классов, как я сделал ниже, но, очевидно, мой синтаксис записи неверен, так как я получаю следующую ошибку:

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')}
   |             ^^^^^^^^

Я пытался применить этот StackOverflow 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

1 Ответ

0 голосов
/ 20 октября 2018

Во-первых, как мы уже рекомендовали в другом вопросе , вам, вероятно, не следует использовать какой-либо класс вообще для этой проблемы, а только параметризованную запись.

Класс не такой, как в ОО, он фактически определяет структуру данных.Он просто определяет некоторые операции, которые могут использовать значения типа экземпляра , чтобы дать вам что-то, но это просто особый случай.Эти значения также могут быть вычислены на лету, и, как правило, не может установить их другое значение.Если вам это нужно, то такого «метода получения» недостаточно, вам также нужен «установщик».Идиоматически в современном Haskell вы могли бы сделать оба сразу: комбинация геттера и сеттера называется линзой .

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

или, короче с векторное пространство ,

import Data.AffineSpace

move :: Movable o => o -> o
move o = o & position %~ (.+^ o^.velocity)
...