4

Heinrich Apfelmus慷慨地附和了这个问题。我曾考虑将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
4

1 回答 1

5

代码有什么问题

你应该使用<$>,而不是<$

  • <$>,也就是fmap将函数应用于右侧事件的值,这就是您在这种情况下要尝试做的事情。
  • <$ 用左侧替换右侧事件的值,为您提供与原始事件同时发生但始终包含相同值的事件。

    注:x <$ e与 相同const x <$> e

为什么你的推理是错误的

我们正在尝试确定子项类型updateGS <$ eInput所在的类型:

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

现在想一想:什么类型必须被实例化abf

  1. 由于updateGS是第一个<$具有类型的参数a,我们必须有

    a ~ PlayerCommand -> GameState -> GameState
    
  2. 同样,eInput第二个参数是<$type f b,所以

    f b ~ Event t PlayerCommand
    

    类型 application associates to the left, 所以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),这解释了类型错误。

于 2012-10-25T17:46:05.917 回答