パッケージの継続モナド変換子の使用を検討することをお勧めしContT
ます。purescript-transformers
ContT
そのパッケージ内の の定義は次のように与えられます
newtype ContT r m a = ContT ((a -> m r) -> m r)
beと be に設定するr
と、コンストラクター内のの型に少し似たものが得られます。Unit
m
Eff eff
asyncGetNumber
(a -> Eff eff Unit) -> Eff eff Unit
これで、必要な効果が含まれていることを確認して、で使用する関数eff
をラップできるはずです
。asyncGetNumber
ContT
asyncGetNumberCont :: ContT Unit (Eff SomeEffects) Number
asyncGetNumberCont = ContT $ \callback ->
asyncGetNumber "/numberLocation" callback
あるいは単に
asyncGetNumberCont = ContT $ asyncGetNumber "/numberLocation"
への引数は、引数としてコールバックを取ることに注意してくださいContT
。
do 記法を使用して、非同期計算を直列に構成できるようになりました。
do n <- asyncGetNumberCont
m <- asyncGetNumberCont
return (n + m)
ContT
非同期計算の並列構成をラップしてサポートするアプリケーション ファンクターを作成することもできます。purescript-node-thunk
この種の機能をそのまま提供するパッケージにも興味があるかもしれません。
編集: 別のオプションはContT
、 とは異なる、外部の型を使用して独自の のような型を作成することEff
です。これは次のように行うことができます。
-- Ignore effects to keep things simple
-- The runtime representation of 'Async a' is a function which takes a callback,
-- performs some side effects an returns.
foreign import data Async :: * -> *
-- Make an async computation from a function taking a callback
foreign import makeAsync
"function makeAsync(f) {\
\ return function(k) {\
\ f(function(a) {\
\ return function() {\
\ k(a)();\
\ };\
\ })();\
\ };\
\}" :: forall a eff. ((a -> Eff eff Unit) -> Eff eff Unit) -> Async a
-- Now we need to define instances for Async, which we can do using FFI
-- calls, for example:
foreign import fmapAsync
"function fmapAsync(f) {\
\ return function (comp) {\
\ return function (k) {\
\ comp(function(a) {\
\ k(f(a));\
\ });
\ };\
\ };\
\}" :: forall a b. (a -> b) -> Async a -> Async b
instance functorAsync :: Functor Async where
(<$>) = fmapAsync
等々。基本的に の実装を繰り返しているため、これはすぐに面倒になりますContT
。
さらに、コンパイラで書き換えルールがサポートされていないと、 で取得するようなインライン バインドを取得する方法がありませんEff
。