События из общего канала связи между потоками

У меня есть программа, которая решает какую-то проблему, и я решил, что хочу следить за тем, что она делает, в удобном графическом интерфейсе. Для графического интерфейса я выбрал Gtk, что означает, что мне нужно запустить цикл mainGUI в выделенном потоке, а остальная часть моей программы займет другой поток. Я думал, что связь между моей программой и другим потоком будет проходить в одном направлении, используя Chan. Далее я решил использовать FRP для обновления графического интерфейса при уведомлении от воркера (логика оригинальной программы в отдельном потоке). Поэтому я попытался написать простой пример с потоками, в котором один поток отправляет IO действий в поток мониторинга, который выполняет действия (отображает их). Вот моя попытка:

import Control.Concurrent
import Control.Monad

import Reactive.Banana
import Reactive.Banana.Frameworks

main = do
    c <- newChan

    forkIO $ do
        actuate <=< compile $ reactimate'
                            <=< changes
                            <=< fromPoll
                            $ readChan c

    forever $ do
        threadDelay 3000000
        putStrLn "sending msg"
        writeChan c $ putStrLn "receiving msg"

Это явно не работает (выводит только sending msg), иначе меня бы здесь не было. Что я делаю не так? Нужно ли мне другое событие, связанное с опросом? Как это сделать?

Я ожидал некоторого чередования копий текстов: sending msg и receiving msg.


Чтобы уточнить, я хочу перейти от

main = do
    c <- newChan

    forkIO . forever . join . readChan $ c

    forever $ do
        threadDelay 3000000
        putStrLn "sending msg"
        writeChan c $ putStrLn "receiving msg"

где каждое сообщение в c :: Chan (IO ()) читается в потоке явно (возможно, с блокировкой) для реактивной обработки сообщений, т. е. описания сети событий/поведений, связанных с элементами графического интерфейса, а затем позволяет потоку выполнять цикл графического интерфейса. Сеть должна будет позаботиться о значениях опроса в канале и запускающих событиях.


Решение, которое я искал (или что-то в этом роде):

main = do
    (msgHandler, msgFire) <- newAddHandler

    forkIO $ do
        actuate <=< compile $ do
            eMsg <- fromAddHandler msgHandler

            reactimate $ putStrLn <$> eMsg

    forever $ do
        threadDelay 3000000
        putStrLn "sending msg"
        msgFire "receiving msg"

person jakubdaniel    schedule 17.05.2016    source источник
comment
Это может быть полезно: wiki.haskell.org/   -  person jkeuhlen    schedule 17.05.2016
comment
Спасибо, меня больше озадачивает часть FRP, а не каналы.   -  person jakubdaniel    schedule 17.05.2016


Ответы (1)


В документации для fromPoll указано

Результирующее поведение будет обновляться всякий раз, когда сеть событий обрабатывает входное событие.

Поскольку события нет, оно никогда не обновляется. fromPoll задуман как быстрый и грязный способ чтения изменяемых данных, но не для обновления сети. Вместо этого документация рекомендует использовать fromChanges. Но так как мы или, потому что мы все равно хотим Event, давайте использовать newEvent, что кажется вполне подходящим: оно позволяет нам создать Event, к которому мы добавляем значения, вызывая Handler (это псевдоним для a -> IO ()).

import Control.Concurrent
import Control.Monad

import Reactive.Banana
import Reactive.Banana.Frameworks

main = do

    c <- newChan

    network <- compile $ do
      (event, handler) <- newEvent
      liftIO $ forkIO $ forever (readChan c >>= handler)
      reactimate event

    forkIO $ actuate network

    forever $ do
        threadDelay 3000000
        putStrLn "sending msg"
        writeChan c $ putStrLn "receiving msg"
person madjar    schedule 17.05.2016