功能性反应香蕉型混淆

Mic*_*ard 4 haskell types frp reactive-banana

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'
Run Code Online (Sandbox Code Playgroud)

所以我研究了(<$),并且局部应用了.看看他建议的例子.我做的越多,我就越认为上面的代码应该起作用了,我感到困惑的是为什么它没有.

这是我认为应该发生的事情:

因为(<$)是类型(<$) :: a -> f b -> f a

和updateGS是类型 updateGS :: PlayerCommand -> GameState -> GameState

并且eInput是类型Event t PlayerCommand

然后不应该updateGS <$ eInput屈服

Event t (GameState -> GameState)

我的理由在某处有缺陷,有人可以指出哪里?

更新:当我尝试使用时,(<$>)我收到了以下错误

outline.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
Run Code Online (Sandbox Code Playgroud)

供参考,这是整个功能

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
Run Code Online (Sandbox Code Playgroud)

ham*_*mar 5

代码有什么问题

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

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

    注意:x <$ e是一样的const x <$> e.

为什么你的推理是错误的

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

(<$)     :: a -> f b -> f a
updateGS :: PlayerCommand -> GameState -> GameState
eInput   :: Event t PlayerCommand
Run Code Online (Sandbox Code Playgroud)

现在想想:什么类型必须a,b并被f实例化?

  1. 因为updateGS是第一个<$有类型的参数a,我们必须拥有

    a ~ PlayerCommand -> GameState -> GameState
    
    Run Code Online (Sandbox Code Playgroud)
  2. 同样,eInput第二个参数是<$哪个类型f b,所以

    f b ~ Event t PlayerCommand
    
    Run Code Online (Sandbox Code Playgroud)

    键入应用程序关联到左侧,因此与之Event t PlayerCommand相同(Event t) PlayerCommand.因此,我们可以确定

    f ~ Event t
    b ~ PlayerCommand
    
    Run Code Online (Sandbox Code Playgroud)
  3. 综合结果的类型f a,我们看到了

    f a ~ Event t (PlayerCommand -> GameState -> GameState)     
    
    Run Code Online (Sandbox Code Playgroud)

因此,updateGS <$ eInput :: Event t (PlayerCommand -> GameState -> GameState)这解释了类型错误.