2016-03-05 68 views
1

我希望有人能夠藉助信號和效果來幫助我。無法觸及榆樹勾選操作

我正在調查信號/效果,並一直在研究榆樹體系結構,尤其是example 8

在這個例子中(據我所知),如果你點擊形狀(S):

  • 信號消息與動作
  • 一起發送到地址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

回答

2

Tick操作永遠不會被觸發,因爲沒有端口將Effects轉換爲Tasks。在您發佈的相關堆棧溢出答案中,正在使用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 
+0

什麼是優秀的答案。感謝您的幫助和其他鏈接 –