2016-04-29 17 views
1

私はEffAffで書かれた以下のプログラマーを持っています。期待どおりに走るつまり、与えられたIntが出力され、非同期計算が行われます。なぜ私のエフェクトは2回呼び出されますか?

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回または常に1回ですが、異なる注文では異なりません)。 – robkuz

+0

合意。上記のプログラムを 'psc-bundle'で実行してpastebinにアップロードできますか? – hdgarrood

答えて

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)); 
     } 
    } 
    }; 
} 
関連する問題