在Scala撰写具有副作用期货的无国籍期货

时间:2016-01-26 08:13:52

标签: scala future side-effects dependency-graph

虽然组合期货具有收益率结构,有些具有副作用,有些没有,我引入了竞争条件,因为取决于副作用的未来不会将该方面的结果影响未来作为论据。

简而言之:

  

未来 b 会读取未来因副作用而更改的值    a ,但未来 a 并未明确依赖于未来 b 的结果,因此可能会在 b 结束之前发生读数。

为了解决这个问题,我的同事介绍了一个虚拟函数,将 b 的结果作为参数,并简单地将其丢弃。这样做是为了使依赖显式化。

实际代码在这里:

  val futureConnection:Future[(Either[String, (Connection)],Boolean)] =
    for {
      scannerUser <- scanner.orFail("Scanning user not found")
      scannedUser <- futureScannedUser.orFail("Scanned user not found")
      existsInAnyDirection <- connections.existsInAnyDirection(scannerUser, scannedUser)
      connection <- connections.createConnection(scannerUser, scannedUser, form.magicWord, existsInAnyDirection)
    } yield {
      (connection, existsInAnyDirection)
    }

在这种情况下,未来 b

connections.existsInAnyDirection(scannerUser, scannedUser)

带有虚拟参数的

和未来 a

connections.createConnection(scannerUser, scannedUser, form.magicWord, existsInAnyDirection)

请注意,existsInAnyDirection中永远不会使用参数createConnection。这有效地创建了依赖关系图,在existsInAnyDirection完成之前无法启动createConnection。

现在提出问题:

是否有更明智的方法使依赖项显式化?

奖励信息

我自己的挖掘告诉我,Scala Futures根本不能很好地处理副作用。处理副作用的The methods on the Future trait返回单位,而从副作用操作中读取的结果很可能,即错误代码,生成的ID,任何其他元信息,真的。

1 个答案:

答案 0 :(得分:0)

Future正在处理推迟计算的副作用,如A => Future[B]

您试图混合几种不同的副作用,但只组成其中一种Future[_]

尝试选择第二个容器,这可以是产品或状态,取决于你的副作用,并考虑组成副作用(可能你需要modand变形金刚)。在您的代码看起来像(最简单的情况)之后:

for {
  scannerUser <- scanner.orFail("Scanning ...")
  (scannedUser, magicWord) <- futureScannedUser.orFail("Scanned ...")      
  connection <- connections.createConnection(scannerUser, scannedUser, magicWord)
} yield {
  (connection, existsInAnyDirection)
}

// OR

for {
  (scannerUser, state) <- scanner.orFail("Scanning ...")
  (scannedUser, nextState) <- futureScannedUser(state).orFail("Scanned ...")      
  connection <- connections.createConnection(scannerUser, scannedUser, nextState)
} yield {
  (connection, existsInAnyDirection)
}