榆树 - 如何根据另一个信号修改一个信号的参数化

时间:2014-07-01 14:00:06

标签: elm elm-signal

如何根据另一个信号参数化一个信号? 例如假设我想根据鼠标的x位置修改fps。类型是:

Mouse.x : Signal Int
fps     : number -> Signal Time

我怎么能让Elm理解这个伪代码的内容:

fps (Mouse.x) : Signal Time

显然,lift在这种情况下不起作用。我认为结果将是Signal (Signal Time)(但我对榆树来说还是一个新手)。

谢谢!

2 个答案:

答案 0 :(得分:4)

序言

fps Mouse.x

导致类型错误的结果是fps需要Int,而不是Signal Int

lift fps Mouse.x : Signal (Signal Int)

你是对的。正如CheatX的回答所提到的,你不能在榆树中使用这些“嵌套信号”。

回答你的问题

好像你要求Standard Libraries中尚不存在的东西。如果我正确理解你的问题,你会想要一个时间(或fps)信号,其时间可以动态改变。类似的东西:

dynamicFps : Signal Int -> Signal Time

使用lift之类的内置函数不能让您自己从类型Int -> Signal Time的函数构造这样的函数。

我认为你有三种选择:

  1. Ask to have this function addedmailing-list上的时间库。 (对于此类功能的请求,功能请求说明有点膨胀,因此您可以跳过不适用的内容)
  2. 使用Ports连接到Elm,从Elm或JavaScript中解决问题。
  3. 找到一种不需要动态更改Time信号的方法。
  4. 我建议选项1 。选项3很难过,你应该能够满足你在榆树中的要求。如果你是榆树的新手,选项2可能不是一个好主意。选项1不是很多工作,邮件列表上的人不会咬人;)

    要详细说明选项2,您是否应该这样做:

    1. 如果指定Signal Int的传出端口和Signal Time的传入端口,则可以在JavaScript中编写自己的动态时间函数。请参阅http://elm-lang.org/learn/Ports.elm
    2. 如果你想从榆树内部做到这一点,那将是一个丑陋的黑客攻击:

      dynamicFps frames = 
        let start = (0,0)
            time  = every millisecond -- this strains your program enormously
            input = (,) <~ frames ~ time
            step (frameTime,now) (oldDelta,old) = 
              let delta = now - old
              in if (oldDelta,old) == (0,0)
                   then (frameTime,now) -- this is to skip the (0,0) start
                   else if delta * frameTime >= second
                          then (delta,now)
                          else (0,old)
        in dropIf ((==) 0) 0 <| fst <~ foldp step start input
      

      基本上,你记得一个绝对时间戳,尽可能快地询问新时间,并检查记忆时间和现在之间的时间是否足够大以适应你想要的时间范围。如果是这样,你发出时间delta(fps给出时间增量)并记住现在作为新的时间戳。因为foldp发出了要记住的所有内容,所以你得到了新的delta和新的时间。因此,使用fst <~只保留delta。但输入时间(可能)比您想要的时间段快得多,因此您从(0,old)获得了大量foldp。这就是dropIf ((==) 0)的原因。

答案 1 :(得分:0)

Elm的类型系统明确禁止嵌套信号[{3}}的第3.2部分。

据我了解FRP,嵌套信号仅在提供某种奉承时才有用(例如,monadic'join'函数)。如果不保留整个信号历史记录,很难实现该操作。