为什么我的效果被调用两次?

问题描述:

我有用Eff s和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现在被称为两次!武汉理工大学?

有人可以解释一下吗?

感谢您的帮助

+0

如果您在'main'中删除对'liftAff'的调用会发生什么?我不认为这是必要的。 (不要原谅这种行为,这确实看起来是错误的;我只是想诊断) – hdgarrood

+0

没有变化。唯一有点“异国情调”的是我使用的是https://github.com/sectore/purescript-webpack-vanilla-hmr。尽管如此,它应该表现一贯(或者总是2次或者总是一次,但是在不同的订单上没有不同) – robkuz

+0

同意。你可以通过'psc-bundle'运行上述程序并将其上传到一个pastebin? – hdgarrood

很可能的情况下的异常被抛出,而不是通过处理误差函数在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)); 
     } 
    } 
    }; 
}