现在,我有一个异步函数,其工作原理如下:

  foo = do
     ayncGetNumber "/numberLocation" \a ->
        (trace <<< show) a

但是这种回调样式(根据我的理解)是不可组合的,我希望它像这样工作
  foo = do
     a <- ayncGetNumber "/numberLocation"
     (trace <<< show) a

或者
  foo = ayncGetNumber "/numberLocation" >>= show >>> trace

但是我不知道如何从回调中逃脱并使其可组合。

最佳答案

您可能要考虑使用ContT包中的延续monad转换器purescript-transformers

该软件包中ContT的定义为

newtype ContT r m a = ContT ((a -> m r) -> m r)

如果将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那样获得内联绑定(bind)。

09-10 23:05