首页 文章

如何解决箭头的一阶约束?

提问于
浏览
7

What I mean by first-order constraint

首先,我将通过箭头的一阶约束来解释我的意思:由于箭头desugar的方式,你不能使用箭头命令中预期箭头命令的本地绑定名称 .

这是一个例子来说明:

proc x -> f -< x + 1 desugars到 arr (\x -> x + 1) >>> f ,同样 proc x -> g x -< () 将desugar到 arr (\x -> ()) >>> g x ,其中第二个 x 是一个自由变量 . GHC user guide解释了这一点并说当你的箭头也是一个monad你可以创建 ArrowApply 的实例并使用 app 来解决这个问题 . 类似的东西, proc x -> g x -<< () 变成 arr (\x -> (g x, ())) >>> app .

My Question

Yampa使用以下类型定义accumHold函数: a -> SF (Event (a -> a)) a . 由于箭头的这个一阶限制,我正在努力编写以下函数:

accumHoldNoiseR :: (RandomGen g, Random a) => (a,a) -> g -> SF (Event (a -> a)) a
accumHoldNoiseR r g = proc f -> do
  n <- noiseR r g -< ()
  accumHold n -< f

上面的定义不起作用,因为 n 在desugaring之后不在范围内 .

或者,类似这个函数,其中对的第一部分 SF 意味着传递给 accumHold 的初始值

accumHold' :: SF (a,Event (a -> a)) -> a
accumHold' = ...

是否有一些我失踪的组合或技巧?或者,如果没有 ArrowApply 实例,是否无法编写这些定义?

tl;dr: 是否可以在yampa中定义 accumHoldNoiseR :: (RandomGen g, Random a) => (a,a) -> g -> SF (Event (a -> a)) aaccumHold' :: SF (a,Event (a -> a)) -> a

Note: SF 没有 ArrowApply 的实例 . 我的理解是,定义一个也没有意义 . 有关详细信息,请参阅"Programming with Arrows" .

3 回答

  • 3

    这是一个理论上的答案 . 请查看Roman Cheplyaka's answer这个问题,它更多地涉及您要实现的实际细节 .


    n 超出范围的原因是,因为它在范围内使用,所以你可以使用monad中的 bind>>= . 它是使用先前计算的结果作为下一个的功能输入,使得像monad一样强大 .

    因此,当您可以创建ArrowApply实例时,您可以将 n 作为函数参数提供给后续箭头 .

    Chris Kuklewicz在his comment中正确指出 -<< 会将 n 带入范围 - 它也使用 app ,因此您需要一个ArrowApply实例 .

    摘要

    除非您使用ArrowApply . 这就是ArrowApply的用途 .

  • 2

    noiseR 是信号函数;它产生一个随机数流,而不仅仅是一个随机数(为此,你只需使用 randomR 中的 randomR ) .

    另一方面, accumHold 的第一个参数只是一个初始值 .

    所以这不仅仅是一些限制 - 它实际上阻止了您提交类型错误 .

    如果我理解你正在尝试做什么,那么只需使用 randomR 即可 . 否则,请说明您为什么需要 noiseR .

  • 0

    为了帮助其他人了解我如何解决这个问题,我将回答我自己的问题 .

    我试图实现游戏乒乓 . 我想让球每轮以随机速度开始 . 我想用 accumHold 来定义球的速度 . 我有一些像这样的代码:

    ballPos = proc e -> mdo -- note the recursive do
      {- some clipping calculations using (x,y) -}
      ...
      vx <- accumHold 100 -< e `tag` collisionResponse paddleCollision
      vy <- accumHold 100 -< e `tag` collisionResponse ceilingFloorCollision
      (x,y) <- integral -< (vx,vy)
      returnA -< (x,y)
    

    我想用随机值替换100(可能来自 noiseR ) .

    我如何解决这个问题的方法是在方向上积累 collisionResponse 只是翻转标志(最终我想要使用相对于墙/桨的速度角度):

    ballPos = proc (initV, e) -> mdo
      {- some clipping calculations using (x,y) -}
      ...
      (iVx,iVy) <- hold (0,0) -< initV
      vx <- accumHold 1 -< e `tag` collisionResponse paddleCollision
      vy <- accumHold 1 -< e `tag` collisionResponse ceilingFloorCollision
      (x,y) <- integral -< (iVx*vx,iVy*vy)
      returnA -< (x,y)
    

    Lesson Learned:

    您通常可以将要累积的值/状态分隔为描述其更改方式的行为,并将描述其当前值的"magnitude"作为输入进行分类 . 在我的例子中,我将初始速度的大小分开,将其作为信号函数的输入传递,并使用 accumHold 来计算碰撞时球的影响(行为) . 所以不管初始速度是多少,撞到球的墙壁 . 这正是 accumHold 正在积累的东西 .

相关问题