我有以下用Eff
和Aff
s编写的程序。哪个按预期运行。也就是说,它打印出给定的Int
并进行异步计算。
type JsonResponse = AffjaxResponse Json
access :: forall e m. Aff (ajax :: AJAX | e) (Either Error JsonResponse)
access = attempt $ get "http://localhost:8080/livesys/Robert"
staging :: forall e. Int -> Eff (console :: CONSOLE | e) Int
staging i = do
liftEff $ log $ ">>" ++ show i
return i
main :: forall a. Int -> Aff (ajax :: AJAX, console :: CONSOLE| a) Int
main state = do
s <- liftEff $ staging state
a <- liftAff access
return s
如果我改变了main
内的呼叫顺序,那么就会发生一些神秘的事情:
main :: forall a. Int -> Aff (ajax :: AJAX, console :: CONSOLE| a) Int
main state = do
a <- liftAff access
s <- liftEff $ staging state
return s
函数staging
现在被称为两次! WUT?
有人可以解释一下吗?
感谢您的帮助
答案 0 :(得分:0)
可能是一个异常被抛出而不是由Aff实例中的错误函数处理的情况。当与attempt
一起使用时,这会导致成功函数的重复调用。
module Main where
import Prelude
import Data.Either (Either(..))
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (log)
import Control.Monad.Eff.Exception (Error, EXCEPTION, throwException, error)
import Control.Monad.Aff (Aff, makeAff, liftEff', launchAff, attempt)
raise = throwException <<< error
myAff :: forall e. Aff e String
myAff = _unsafeInterleaveAff $ makeAff doIt
where
doIt _ success = do
log "operation"
raise "it's dead jim"
success "done"
main = do
launchAff $ do
liftEff' $ log "start"
myAff
foreign import _unsafeInterleaveAff :: forall e1 e2 a. Aff e1 a -> Aff e2 a
此代码会导致doIt
被调用两次,但当Aff调用被撤消时则不会。
其他:
虽然这个功能确实有点奇怪。也许用更像这样的attempt
来替换它?
exports._attempt = function (Left, Right, aff) {
return function(success, error) {
var affCompleted = false;
try {
return aff(function(v) {
affCompleted = true
success(Right(v));
}, function(e) {
affCompleted = true
success(Left(e));
});
} catch (err) {
if (affCompleted) {
throw err;
} else {
success(Left(err));
}
}
};
}