无法达到榆树刻度线操作

时间:2016-03-05 10:00:53

标签: signals effects elm keyboard-input

我希望有人可以通过信号和效果来帮助我。

我正在研究信号/效应并一直在研究榆树架构,特别是example 8

在这个例子中(据我所知),如果你点击形状:

  • 将信号消息与动作一起发送到地址
  • 更新
  • 时会触发SPIN操作
  • 如果他的形状当前没有动画,也会调用Tick。

我试图复制完全相同的流程(使用类似的代码),但我没有点击按钮并使用HTML包,而是想使用空格键发送信号。

在我的代码中,空格键会向Punch操作发送信号。就像例8一样,我还想调用Tick并更新模型中的debounceState

您在我的评论中会看到我可以接触Punch行动,但我似乎无法前往Tick

我看过this question,但由于我使用的是键盘信号而不是榆树StartApp,我认为它不适用。

如果有人可以解释为什么我在我的例子中无法触及Tick,我会非常感激。

module Main (..) where

import Graphics.Element exposing (..)
import Time exposing (Time, second)
import Effects exposing (Effects)
import Keyboard


type alias DebounceState =
  Maybe
    { prevClockTime : Time
    , elapsedTime : Time
    }


type alias Model =
  { punching : Bool
  , count : Int
  , randomString: String
  , debounceState : DebounceState
  }


duration = second


-- MODEL


initialModel : ( Model, Effects Action )
initialModel =
  ( { punching = False
    , count = 0
    , randomString = ""
    , debounceState = Nothing
    }
  , Effects.none
  )


model : Signal ( Model, Effects Action )
model =
  Signal.foldp update initialModel (punch Keyboard.space)


-- ACTIONS


type Action
  = NoOp
  | Punch Bool
  | Tick Time


-- UPDATE


update : Action -> ( Model, Effects Action ) -> ( Model, Effects Action )
update action ( model, fx ) =
  case action of
    NoOp ->
      ( model, Effects.none )

    Punch isPunching ->
      case model.debounceState of
        Nothing ->
          ( { model |
              punching = isPunching
              , count = model.count + 1 }, Effects.tick Tick )

        Just _ ->
          ( { model |
              punching = isPunching
              , count = model.count + 2 }, Effects.none )

    -- I don't seem to reach `Tick` at all
    -- You'll notice that I try to apply a value to `randomString` in the
    -- conditional to indicate where I end up
    Tick clockTime ->
      let
        newElapsedTime =
          case model.debounceState of
            Nothing ->
              0

            Just {elapsedTime, prevClockTime} ->
              elapsedTime + (clockTime - prevClockTime)
      in
        if newElapsedTime > duration then
          ( {model | randomString = "foo"} , Effects.none )
        else
          ( {model | randomString = "bar"} , Effects.tick Tick )


-- SIGNAL


punch : Signal Bool -> Signal Action
punch input =
  Signal.map Punch input


-- VIEW

view : ( Model, Effects Action ) -> Element
view model =
  show model


main : Signal Element
main =
  Signal.map view model

将其直接粘贴到Try Elm

1 个答案:

答案 0 :(得分:2)

Tick操作永远不会被触发,因为没有端口将Effects转移到Tasks。在您发布的相关Stack Overflow答案中,正在使用StartApp,因此很容易连接端口。

由于您没有使用StartApp,因此您需要手动执行一些操作。现在,你的model只是在听键盘空间信号。您需要连接信号处理,以便您的效果一直回到触发update功能。

您需要一个邮箱来协调信号。

actions : Signal.Mailbox (List Action)
actions =
  Signal.mailbox []

请注意,此邮箱是根据操作列表定义的。这是将效果转化为任务的复杂部分之一,它是explained here

现在,您需要一个端口,它接收(Model, Effects Action)元组的第二部分并将其转换为Task

port effects : Signal (Task.Task Effects.Never ())
port effects =
  Signal.map (Effects.toTask actions.address << snd) model

该端口现在会将您的Tick操作发送到邮箱,但我们仍然无法连接您的模型以收听键盘空间键和此新邮箱。为此,我们将使用Signal.mergeMany

signals : Signal Action
signals =
  let
    singleAction list =
      case list of
        [] -> NoOp
        (a::_) -> a
  in
    Signal.mergeMany
      [ punch Keyboard.space
      , Signal.map singleAction actions.signal
      ]

singleAction函数中正在进行的有趣业务让我们了解Effects.toTask迫使我们使用Actions列表而不是单Action这一事实。看一下这些文档,很明显我们只是从列表中取出第一个元素是安全的。

所以现在我们有一个由键盘空格键和Tick动作触发的信号。最后一部分是让model听取信号,而不只是键盘。

model : Signal ( Model, Effects Action )
model =
  Signal.foldp update initialModel signals