我希望有人可以通过信号和效果来帮助我。
我正在研究信号/效应并一直在研究榆树架构,特别是example 8。
在这个例子中(据我所知),如果你点击形状:
SPIN
操作
我试图复制完全相同的流程(使用类似的代码),但我没有点击按钮并使用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。
答案 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