2

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

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

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

fps (Mouse.x) : Signal Time

显然,lift在这种情况下不起作用。我认为结果会是Signal (Signal Time)(但我对 Elm 还是很陌生)。

谢谢!

4

2 回答 2

4

前言

fps Mouse.x

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

lift fps Mouse.x : Signal (Signal Int)

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

回答你的问题

似乎您要的是Standard Libraries中尚不存在的东西。如果我正确理解您的问题,您想要一个时间(或 fps)信号,其时间可以动态更改。就像是:

dynamicFps : Signal Int -> Signal Time

使用内置函数 likelift并不能让您自己从 type 的函数构造这样的函数Int -> Signal Time

我认为您在这里有三个选择:

  1. 要求将此功能添加邮件列表上的时间库中。(功能请求说明对于此类功能的请求有点臃肿,因此您可以跳过不适用的内容)
  2. 从 Elm 或 JavaScript 中解决此问题,使用端口连接到 Elm。
  3. 找到一种不需要动态变化Time信号的方法。

我建议选项 1。选项 3 是可悲的,你应该能够满足你在 Elm 中的要求。如果您是 Elm 新手,选项 2 可能不是一个好主意。选项 1 的工作量不大,邮件列表上的人也不会咬人 ;)

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

  1. 如果您指定一个传出端口Signal Int和一个传入端口,Signal Time您可以在 JavaScript 中编写自己的动态时间函数。请参阅http://elm-lang.org/learn/Ports.elm
  2. 如果您想在 Elm 中执行此操作,则需要更丑陋的 hack:

    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
    

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

于 2014-07-02T08:34:05.667 回答
0

Elm 的类型系统 [本文的第 3.2 部分] 明确禁止嵌套信号。

据我了解 FRP,嵌套信号仅在提供某种讨人喜欢的情况下才有用(例如,monadic 'join' 函数)。如果不保留整个信号历史记录,就很难实施该操作。

于 2014-07-01T15:30:53.000 回答