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)
代码有什么问题
你应该使用<$>,而不是<$.
<$>,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实例化?
因为updateGS是第一个<$有类型的参数a,我们必须拥有
a ~ PlayerCommand -> GameState -> GameState
Run Code Online (Sandbox Code Playgroud)同样,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)综合结果的类型f a,我们看到了
f a ~ Event t (PlayerCommand -> GameState -> GameState)
Run Code Online (Sandbox Code Playgroud)因此,updateGS <$ eInput :: Event t (PlayerCommand -> GameState -> GameState)这解释了类型错误.