2015-10-14 41 views
4

我正在嘗試在netwire 5「正確地」執行一組動態導線。 我已閱讀wires of wires問題的答案,我不特別喜歡該示例中的代碼如何依靠Event轉換爲在上顯示非空的行爲,恰好一個執行stepWireHaskell Netwire:正確完成電線的導線

因此,我想要通過Event s在動態設置中添加和刪除導線,並且希望不會攻擊Unsafe.Event或同等hackery。讓我們放棄對簡單去除一部分,只是使它可以添加Wire S:

dynWireSet1 :: (Monad m, Monoid s) 
      => Wire s e m (a, Event (Wire s e m a b)) [b] 

每個事件增加了一個新的導線電線隱藏在內部的(初始爲空)列表(或其他組),他們全部運行,全部獲得類型爲a的輸入,並將其輸出收集到列表中。

的運行部分是比較容易的,具有googleable實例,例如:以上

dynWireSet1 = runWires1 [] 
runWires1 :: (Monad m, Monoid s) 
      => [Wire s e m a b] 
      -> Wire s e m (a, Event (Wire s e m a b)) [b] 
runWires1 wires = mkGen $ \session (input, event) -> do 
    stepped <- mapM (\w -> stepWire w session (Right input)) wires 
    let (outputs, newwires) = unzip stepped 
    return (sequence outputs, runWires1 newwires) 

實施例忽略事件。我懷疑 不可能使用轉換函數中的事件,而不是 函數使用Unsafe.Event。那是對的嗎? I 想避開Unsafe.Event

當我退後一步,看看建議使用事件方式,我看到一個 功能,看起來非常有前途:

krSwitch :: Monad m 
     => Wire s e m a b 
     -> Wire s e m (a, Event (Wire s e m a b -> Wire s e m a b)) b 

現在,如果我開始什麼用簡化runWires:

runWires2 :: (Monad m, Monoid s) 
      => [Wire s e m a b] 
      -> Wire s e m a [b] 
runWires2 wires = mkGen $ \session input -> do 
    stepped <- mapM (\w -> stepWire w session (Right input)) wires 
    let (outputs, newwires) = unzip stepped 
    return (sequence outputs, runWires2 newwires) 

,並dynWireSet一個krSwitch:

dynWireSet2 :: (Monad m, Monoid s) 
      => Wire s e m (a, Event (Wire s e m a b)) [b] 
dynWireSet2 = krSwitch (runWires2 []) . second (mkSF_ (fmap addWire)) 
addWire :: Wire s e m a b -> Wire s e m a [b] -> Wire s e m a [b] 
addWire = undefined 

我快到了!現在,如果我只能通過a (:)而不是runWires2並將新電線插入newwires,那麼我將全部設置!但在一般情況下,這是不可能的。其實,fmap超過WGen只是fmaps以上的輸出,如果我說得對。無用。

現在,這是我的想法。我們來介紹一個data Wire的新變體,我暫時將其稱爲WCarry g st,因爲它將以不同的數據類型傳送其內部狀態。它的轉移函數將是給定的初始狀態下的類型

((a, c) -> m (b, c)) 

和,的,構造會產生線是這樣的:

mkCarry :: Monad m => ((a, c) -> m (b, c)) -> c -> Wire s e m a b 
mkCarry transfun state = mkGenN $ \input -> do 
    (output, newstate) <- transfun (input, state) 
    return (Right output, mkCarry transfun newstate) 

僅引入WCarry類型,而不是WGen類型到所得絲。根據mkCarry很容易重寫runWires

然後,FMAP實例將是這個樣子:

fmap f (WCarry g st) = WCarry g (fmap f st) 

它將改變「隱藏在」狀態對象,我們就可以使用krSwitch功能有意義的這種Wire S,調整他們的內部狀態而不會失去先前的價值。

這是否有意義?如果我想要以更簡單的方式進行操作,請諮詢!如果我說的是有道理的話,我怎麼去解決呢?是可以在本地擴展data Wire定義與WCarry,並擴展添加有趣的類實例與相應的定義?任何其他建議?

謝謝。

回答

2

我正在使用Netwire和我遇到了完全相同的問題,所以我認爲這將有助於回答這個問題。我同意使用(安全)事件是正確的選擇。不過我不喜歡加入WCarry,它看起來不太直觀。

你其實非常接近答案。製造addWire的關鍵在於你不想修改舊線。你想要的是與給定的子線的輸出添加創建一個新的線,所以這可能是你正在尋找:

addWire w ws = fmap (uncurry (:)) (w &&& ws) 

這根電線輸送到兩個電線,然後加入輸出。希望能幫助到你!

+0

它適用於組合現有設置和新線的輸出。但在下一步中,我顯然希望從集合中刪除導線(例如使用地圖來表示)。我可以按照您的建議刪除不需要的輸出,但不會導致內存泄漏? – crosser

+0

評論自己的評論,也許使用懶惰的地圖會緩解內存泄漏問題?會嗎? – crosser

+1

當您想要移除'w'時,您可以讓'w &&& ws'響應一個切換回'ws'的事件。 – Mokosha