Функциональный реактивный банан - путаница типов

Генрих Апфельмус щедро поддержал эта проблема. Я рассматривал возможность использования accumB в качестве решения, но думал, что будет ошибка типа. В любом случае, попробовав его предложение, я получил ошибку типа.

let bGameState :: Behavior t GameState
    bGameState = accumB initialGS $ updateGS <$ eInput

yields the error

 Couldn't match expected type `GameState'
             with actual type `PlayerCommand'
 Expected type: GameState -> GameState
   Actual type: PlayerCommand -> GameState -> GameState
 In the first argument of `(<$)', namely `updateGS'
 In the second argument of `($)', namely `updateGS <$ eInput'

Итак, я изучил (<$) и возился с частичным применением. Посмотрел предложенные им примеры. Чем больше я это делал, тем больше я думал, что приведенный выше код должен работать, и я был сбит с толку, почему это не так.

Вот что я думаю должно происходить:

так как (<$) имеет тип (<$) :: a -> f b -> f a

а updateGS имеет тип updateGS :: PlayerCommand -> GameState -> GameState

а eInput относится к типу Event t PlayerCommand

то не должен updateGS <$ eInput уступать

Event t (GameState -> GameState) ?

Мои рассуждения где-то ошибочны, может кто-нибудь указать где?

Обновление: когда я попытался использовать (<$>), я получил следующую ошибку

план.hs:158:21:

Could not deduce (t ~ t1)
from the context (Frameworks t)
  bound by a type expected by the context:
             Frameworks t => Moment t ()
  at outline.hs:(153,42)-(159,93)
  `t' is a rigid type variable bound by
      a type expected by the context: Frameworks t => Moment t ()
      at outline.hs:153:42
  `t1' is a rigid type variable bound by
       the type signature for bGameState :: Behavior t1 GameState
       at outline.hs:158:8
Expected type: Behavior t1 GameState
  Actual type: Behavior t GameState
In the expression: accumB initialGS $ updateGS <$> eInput
In an equation for `bGameState':
    bGameState = accumB initialGS $ updateGS <$> eInput

для справки, вот вся функция

makeNetworkDescription :: AddHandler PlayerCommand -> IO EventNetwork
makeNetworkDescription addCommandEvent = compile $ do
   eInput <- fromAddHandler addCommandEvent
   let bCommand = stepper Null eInput
   eCommandChanged <- changes bCommand
   let bGameState :: Behavior t GameState
       bGameState = accumB initialGS $ updateGS <$> eInput
   reactimate $ (\n -> appendFile "output.txt" ("Command is " ++ show n)) <$>    
   eCommandChanged

person Michael Litchard    schedule 25.10.2012    source источник
comment
Вторая проблема не связана с первой. Попробуйте удалить сигнатуру типа из bGameState — она слишком полиморфна (на t есть неявная forall).   -  person hammar    schedule 25.10.2012


Ответы (1)


Что не так с кодом

Вы должны использовать <$>, а не <$.

  • <$>, также известный как fmap, применяет функцию к значению правых событий, что вы и пытаетесь сделать в данном случае.
  • <$ заменяет значение событий с правой стороны на значение с левой стороны, давая вам событие, которое происходит в то же время, что и исходное, но всегда содержит одно и то же значение.

    Примечание: x <$ e совпадает с const x <$> e.

Почему ваши рассуждения неверны

Мы пытаемся определить тип updateGS <$ eInput, где типы подтерминов:

(<$)     :: a -> f b -> f a
updateGS :: PlayerCommand -> GameState -> GameState
eInput   :: Event t PlayerCommand

Теперь подумайте: для каких типов должны быть созданы экземпляры a, b и f?

  1. Поскольку updateGS является первым аргументом <$, который имеет тип a, мы должны иметь

    a ~ PlayerCommand -> GameState -> GameState
    
  2. Точно так же eInput является вторым аргументом <$, который имеет тип f b, поэтому

    f b ~ Event t PlayerCommand
    

    Тип application ассоциируется слева, поэтому Event t PlayerCommand совпадает с (Event t) PlayerCommand. Следовательно, мы можем определить, что

    f ~ Event t
    b ~ PlayerCommand
    
  3. Сопоставляя тип результата, f a, мы видим, что

    f a ~ Event t (PlayerCommand -> GameState -> GameState)     
    

Следовательно, updateGS <$ eInput :: Event t (PlayerCommand -> GameState -> GameState), что объясняет ошибку типа.

person hammar    schedule 25.10.2012
comment
Проголосуйте за образование, но см. выше, что произошло, когда я попытался использовать ‹$›. - person Michael Litchard; 25.10.2012