2011-06-30 38 views
12

對不起,我剛開始考察反應香蕉和玻璃鋼。反應香蕉行爲

反應香蕉的作者根據我的建議做了this的例子,在這個例子中他創建了一個可以增加和減少的計數器。他使用累積事件的accumE函數。我認爲我能夠對Event類型有所幫助,並且能夠用它測試很多事情,但後來我記得還有Behavior。我研究過它,但似乎這種行爲意味着在類似的情況下使用;修改現有的變量,就像accumE用於事件一樣。

行爲是什麼意思,它有什麼用途?

+0

https://github.com/HeinrichApfelmus/Haskell-BlackBoard/blob/master/reactive-banana-wx/src/Counter.hs is 404 –

回答

7

語義,你有

Behavior a = Time -> a 

也就是說,Behavior aa型隨時間變化的值。一般來說,你根本不知道 a Behavior a會改變,所以它變成一個相當糟糕的選擇來更新文本字段的點擊按鈕。也就是說,很容易得到這一行爲來表示計數器例子中數字的當前值。只需在事件流上使用stepper,或者使用accumB而不是accumE以相同方式從頭開始構建。

通常,您連接到輸入和輸出的東西始終爲Event s,所以Behavior在內部用於中間結果。

假設在給定的例子中,你想添加一個新的記憶當前值的按鈕,比如簡單計算器上的記憶功能。你會開始時通過添加內存按鈕和文本字段的值記住:

bmem <- button f [text := "Remember"] 
memory <- staticText f [] 

你需要能夠在任何時間,要求的電流值,使您的網絡中,你會添加行爲來表示它。

let currentVal = stepper 0 counter 

然後你可以掛鉤的事件,並使用apply讀取行爲的每個記住按下按鈕時的價值,併產生與價值觀的該序列的事件。

emem <- event0 bmem command 
let memoryE = apply (const <$> currentVal) emem 

最後,掛鉤這一新的事件來輸出

sink memory [text :== ("", show <$> memoryE)] 

如果你想在內部使用的內存,然後再你想要爲它的當前值Behavior太...但因爲我們只用它將它連接到輸出,所以我們現在只需要一個事件。

這有幫助嗎?

+0

是的,我相信這正是我想要的 – Masse

+0

雖然也許是誤導,正如我的答案中所解釋的。 – Conal

6

通常,行爲是一段時間內會發生變化的值。這是一個連續的值,其中事件是離散值。在行爲的情況下,值總是存在。 例如:文本框上的文本是行爲,因爲文本可以在一段時間內更改,但會有當前值,其中作爲事件中的鍵盤筆劃,因爲您無法爲其「當前值」查詢鍵盤筆劃「價值。

+1

正如我在我的回答中所提到的,行爲實際上並不是很好的匹配用於設置類似於反應式香蕉的文本字段,因爲調用底層圖形庫函數來設置需要在離散時間發生的值,所以實際上需要事件來通知您何時發生更改。 –

+0

我和Ankur在這裏,正如我的回答中所反映的。 – Conal

11

我同意Ankur而不是Chris:文本框是一段時間的價值,所以自然而然地想成爲一種行爲而不是事件。 Chris給出的不太自然的事件選擇的原因是實施問題等(如果準確的話)反應性香蕉實施的不幸的人造物。我寧願看到改進的實現比不自然地使用範例。

除了語義上的適合之外,選擇Behavior而非Event的實用性非常有用。例如,您可以使用Applicative操作(例如,liftA2)將時變文本框值與其他時變值(行爲)組合。

+0

請注意,文本框的價值本質上是一個*不連續*時間函數,我懷疑這是實現問題和「行爲」不太自然的看法的原因。這與運動圖像在屏幕上的位置不同,這自然是連續的。文本框的*微分*是「行爲」還是「事件」? –

+0

你真的是指dis /連續時間函數,還是dis/continuous time函數?行爲是關於連續時間的函數,而不是連續的時間函數。 – Conal

+0

因爲它需要離散值,談論佔用時間跨度值的變化是沒有意義的。如果隨時間的文本框值是* tb(t)*,並且從* tb(n)=「ab」*到* tb(n + 0.5)=「abc」*,則變化是(++「c 「)。如果* tb(n + 0.25)= X *,從「ab」到X加上從X到「abc」的變化應該等於(++「c」)。我認爲沒有語義上有意義的方法可以將(++「c」)分成兩半,所以變化必須發生在X之前或之後。重複參數顯示變化必須具有持續時間0,使* tb(t)*一個不連續的功能。 –

6

圖書館作者講。 :-)

顯然,Chris Smith可以閱讀頭腦,因爲他準確地描述了我的想法。 :-)

但是ConalArthur也有一點。從概念上講,計數器是一個隨時間變化的值,而不是一系列事件發生。因此,將其視爲Behavior會更合適。

不幸的是,行爲沒有提供任何關於他們什麼時候會改變的信息,都是「僅限於輪詢」。現在,我可以嘗試實現各種聰明的方案,最大限度地減少輪詢,從而允許GUI元素的有效更新。 (Conal在original paper中做了類似的事情。)但是我採用了一種「沒有魔力」的理念:圖書館用戶應負責通過事件本身管理更新。

我目前設想的解決方案是提供一個第三類型除了EventBehavior,即Reactive(名稱如有更改),這體現了雙方的特質:從概念上講,它是隨時間變化的值,但它也涉及帶有通知變化的事件。一種可能的實現是

type Reactive a = (a,Event a) 

changes :: Reactive a -> Event a 
changes (_, e) = e 

value :: Reactive a -> Behavior a 
value (x, e) = stepper x e 

這是毫不奇怪,這恰恰是類型sink預期。這將包括在反應式香蕉圖書館的未來版本中。

編輯:我已經發布了反應香蕉version 0.4其中包括新型,現在叫Discrete

+0

由於純粹的操作/實現原因,我很抱歉看到語義模型和接口變得更加複雜。 – Conal

+0

如果你堅持使用這種新的實現驅動類型,我建議不要使用名稱「Reactive」,因爲與我在* [Push-pull functional reactive programming]中使用的語義不一致(http://conal.net/papers/push-pull-frp /)*可能會導致混淆。 – Conal

+0

隨着時間的推移直接更新UI的價值無論如何可以說是概念上的不匹配。更新關心更改,而不是值。在我對Conal的回答的評論中概述的動機是,我發現系統中的許多元素在被視爲一種派生類型時具有更清晰的語義。實際上應用更新可能會進一步包括自上次UI更新以來的時間段內求和導數,但這是一個明確的積分,並且在概念上與原始函數不同。 –