2015-09-25 3 views
1

Итак, я написал свою собственную реализацию StateT, потому что я не мог заставить трансформаторы правильно компилироваться в Haste. Я думаю, хотел получить javascript setInterval, работающий внутри моей государственной монады. Вот вызов ffi: setInterval.Функция интервала записи для монады StateT в ускорении

jsInterval :: Int -> IO() -> IO Int 
jsInterval = ffi "(function(t,f){window.setInterval(f,t);})" 

Я не мог думать в любом случае, чтобы получить результат m назад после того, как она передается jsInterval. Поэтому я попытался использовать IORefs.

interval :: Int -> StateT s IO() -> StateT s IO Int 
interval i m = StateT $ \s -> do 
    ref <- newIORef Nothing 
    id_ <- jsInterval i $ do 
         (_, s') <- runStateT m s 
         writeIORef ref (Just s') 
    s' <- readIORef ref 
    return (id_, s') 

Это не работает, потому что оно хранит исходное состояние. Чтение произошло до написания. Поэтому я написал функцию, которая будет опроса в цикле до тех пор, пока не будет написано IORef, но это просто вечно вечно.

interval :: Int -> StateT s IO() -> StateT s IO Int 
interval i m = StateT $ \s -> do 
    ref <- newIORef Nothing 
    id_ <- jsInterval i $ do 
         (_, s') <- runStateT m s 
         writeIORef ref (Just s') 
    s' <- go ref 
    return (id_, s') 
    where 
    go ref = do 
     s <- readIORef ref 
     case s of 
     Nothing -> go ref 
     Just s' -> return s' 

Возможно ли реализовать эту функцию? Я попробовал написать экземпляр MonadEvent для StateT, но это также не увенчалось успехом.

+0

Я не думаю, что это возможно. Вы можете дождаться, когда 'setinterval' вызовет его функцию _once_ с помощью' MVar'. Но следующие вызовы функций не могут влиять на состояние внутри 'StateT'. – chi

+0

Не связано с фактическим вопросом, который ответил @drquicksilver замечательно, но я хочу указать, что обертка 'setInterval' вручную не нужна; вы должны использовать [setTimer] (http://hackage.haskell.org/package/haste-compiler-0.5.1.3/docs/Haste.html#v:setTimer). – valderman

+0

@valderman Я попытался это сделать, но столкнулся с аналогичной проблемой, поскольку мне не удалось реализовать MonadEvent для StateT. – DiegoNolan

ответ

3

Действие IO, которое вы передаете на свой FFI'ed jsInterval, является простым действием IO. Если вы реализуете это действие с помощью runStateT, вы просто запускаете небольшое «локальное» StateT. Он не имеет отношения к прилагаемому коду.

Это общая проблема с обратными вызовами и монадными стеками - обратные вызовы (в том смысле, что IO() параметр jsInterval является обратным вызовом) имеют фиксированные монады выбрали в их определении, и они не имеют возможностей обобщить на другие монадических эффекты вы можете использовать в другом месте.

Поскольку обратные вызовы - в общем случае - могут быть вызваны в любое время, в том числе несколько раз подряд, в разных потоках, после того, как функция вызова завершилась и состояние было уничтожено - вы можете видеть, что это трудная проблема для решения в целом.

Прагматичный ответ, как вы пробовали, просто использовать IORef; создайте IORef в прилагаемом действии и позвольте обратному сообщению изменить его. Вы все равно можете написать обратный вызов в стиле StateT, если хотите - просто извлеките состояние из IORef и передайте его runStateT. Ваш код не делает этого, вы только ссылки на параметр s от верхнего уровня: вам нужно использовать IORef, что-то вроде этого:

id_ <- jsInterval i $ do 
        current_s <- readIORef ref 
        (_, new_s) <- runStateT m current_s 
        writeIORef ref (new_s) 

Вы не можете использовать Maybe, если вы не подготовлены научить действию m, как справиться с Maybe - ему нужно иметь дело с Nothing, поэтому, возможно, вы хотите, чтобы у него был тип StateT (Maybe s) IO()?

Вторая логическая проблема (?) С вашим кодом состоит в том, что, конечно, s, возвращаемый interval, еще не был изменен - ​​код setInterval не может быть запущен до тех пор, пока javascript не вернется в свой цикл простоя.

Общая проблема проходящих обратных вызовов обсуждалось несколько раз на протяжении многих лет, см:

https://mail.haskell.org/pipermail/haskell-cafe/2007-July/028501.html http://andersk.mit.edu/haskell/monad-peel/ http://blog.sigfpe.com/2011/10/quick-and-dirty-reinversion-of-control.html

и т.д.

 Смежные вопросы

  • Нет связанных вопросов^_^