Scala 类型系统帮助 : Let a failure cascade up the stack

标签 scala functional-programming type-systems

我已经和这头野兽搏斗了几天,需要一些指导。我的原始代码太大而且太麻烦,所以我试图在这里创建所有部分并且它(几乎)编译,我在下面编写的代码中遇到了一些错误。

我想要做的是让“失败”将链级联到我的 API 层。该域围绕连接到后端以通过 MAC 地址获取设备健康检查列表。一个账号有多个设备,一个设备有多个mac地址。只有主 mac 会从后端系统获得成功响应。

Update 1: By Failure here I mean connection issues to the backend client. an Unknown mac (i.e. a mac that's not found/resolved) is not considered a failure. It should be reported as a Success.



这是我迄今为止重新创建的内容,以供您模拟我的系统。可以切换第 18 行和第 19 行以查看不同的条件。
    import scala.util._

    trait EquipmentStatus { val mac: String }
    case class Offline(mac: String) extends EquipmentStatus
    case class Online(mac: String) extends EquipmentStatus
    case class Unknown(mac: String) extends EquipmentStatus

    case class EquipmentHealth(mac: String, status: EquipmentStatus)

    case class Account(number: Int, equipments: List[Equipment])
    case class Equipment(macs: List[String]) { 
        def primaryMacs = macs.filter(_.endsWith("00")) 
    }

    object StatusChecker { 
        def checkBatchStatuses(macs: List[String]): 
        Try[List[EquipmentStatus]] = 
            //Success(macs.map(Online(_))) 
            Failure(new Exception("Connection Timed Out"))
    }


    object DeviceService {

        def getMacsByAccount(macs: List[String], equipments: List[Equipment]): Try[List[EquipmentHealth]] = {

            for {
                mac <- macs 
                equipment <- equipments.filter(_.macs.contains(mac))
                statuses <- StatusChecker.checkBatchStatuses(equipment.primaryMacs)
            } yield resolveStatus(statuses, mac)// ######### HOW DO I CONVERT/COLLECT Try[EquipmentHealth] to Try[List[EquipmentHealth]] AND ALSO ALLOW Try[Exception()] TO PROPAGATE UP AS WELL? 

        }

        def resolveStatus(statuses: List[EquipmentStatus], mac: String): Try[EquipmentHealth] = {

            statuses.partition(_.mac == mac) match {
                case (Nil, Nil) => Success(EquipmentHealth(mac, Unknown(mac)))
                case (List(one), Nil) => Success(EquipmentHealth(mac, one))
                case _ => Success(EquipmentHealth(mac, Unknown(mac)))
            }
        }
    }


    val equipments = List(Equipment(List("mac100", "mac222")), Equipment(List("mac333", "mac400")))
    val exampleAcc = Account(1234, equipments)

    DeviceService.getMacsByAccount(List("mac222"), exampleAcc.equipments)

在我的代码库中,Try 实际上是一个自定义的 Boxed (Either) 类型,包含成功和失败。我的理解能力欠缺。我想要的是从 Try[EquipmentHealth] 到 Try[List[EquipmentHealth]]。

我把这弄得太复杂了吗?有没有我没有看到的更简单的方法?

最佳答案

你不是只想拥有List[Try[EquipmentStatus]]而不是 Try[List[EquipmentStatus]] ?前者不允许从单个故障中恢复。理解总是产生类似迭代的结果,你不能返回 Try[List[Something]]从中。

为了给出更详细的答案,我需要您澄清预期的行为。你的DeviceService.resolveStatus很奇怪只能导致成功,这主要是因为您没有保留有关哪些查询失败的任何信息,因此您无法在“此查找失败”和“此 MAC 地址未知”之间做出决定。我认为应该删除未知案例,我们总是假设如果没有成功返回,那么它就是失败。否则,您需要存储更多信息,例如 List[(String, Try[EquipmentStatus]]其中元组的第一个元素是被查询的 MAC 地址(或者,为了更好的性能,使用一个键是地址的映射)。

关于Scala 类型系统帮助 : Let a failure cascade up the stack,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53791743/

相关文章:

concurrency - future 永远不会解决并兑现 promise

erlang - 为什么透析器发现我的类型规范无效?

haskell - 如何在与 Haskell 的 System-Fw 不匹配的类型系统中进行编程?

scala - 在 Spark 中广播 Joda DateTime 时出错

json - 从spark scala中的多行文件中读取JSON文件

Scala:以 Try[T] 作为返回类型链接多个函数

haskell - 如何在纯函数中跳过不必要的 IO?

scala - 实际上可以弃用 Scala 案例类字段吗?

java - 在 O(1) 打开文件描述符中迭代 scala/java 中的文件