Scala中的成功/失败链模式

我有这样的工作流程:

parse template -> check consistency
                                    -> check conformance of one template to another
parse template -> check consistency

这些步骤中的任何一个都可能失败.我想在Scala中实现它,最好是让并行分支独立评估,合并它们的错误.也许是一种monadic风格,但我也对一些一般的OOP模式感到好奇.目前我有多种变体硬编码用于链接这样的各种操作

def loadLeftTemplateAndForth (leftPath : String, rightPath : String) = {
  val (template, errors) = loadTemplate(leftPath)
  if(errors.isEmpty) loadRightTemplateAndForth(template, rightPath)
  else popupMessage("Error.")
}

我打赌它必须是某种反模式.这些步骤需要与工作流程脱钩,但我无法想出任何非常优雅的东西,而且必须已经证明了方法.

编辑:
好吧,所以我试图实现这样的事情是不成功的

(((parseTemplate(path1) :: HNil).apply(checkConsistency _) :: ((parseTemplate(path2) :: HNil).apply(checkConsistency _)) :: HNil).apply(checkConformance _)

def checkConformance (t1 : Template)(t2 : Template) : Seq[Error]

然后函数将返回Success(结果)或Failure(错误).我使用的是HLists,但在类型推理规则和其他问题上迷失了方向.虽然看起来我很近.对于知道这些东西的人来说,它可能是一块蛋糕.

编辑:
我终于设法实现了这一点

(parseTemplate("Suc") :: Args).apply(checkConsistency _) :: 
(parseTemplate("Suc") :: Args).apply(checkConsistency _) :: Args)
.apply(checkConformance _)

使用一些非实现的约束,每个函数必须返回我的等效的Either,并且应用函数的错误类型必须是参数’错误类型的子类型.我使用HList,应用程序类型类和包装类Successful / UnsuccessfulArgList完成了它.

最佳答案 这个怎么样?

// Allows conditional invocation of a method
class When[F](fun: F) {
    def when(cond: F => Boolean)(tail: F => F) = 
      if (cond(fun)) tail(fun) else fun
}
implicit def whenever[F](fun: F): When[F] = new When[F](fun)

之后:

parseTemplate(t1).when(consistent _){ 
  val parsed1 = _
  parseTemplate(t2).when(consistent _){ 
    conforms(parsed1, _) 
  }
}

为错误创建一些持有者,并传递它(到parseTemplate,一致,conforms),或使用ThreadLocal.

这里解耦得更多:

(parseTemplate(t1), parseTemplate(t2))
  .when(t => consistent(t._1) && consistent(t._2)){ t =>
    conforms(t._1, t._2) 
  }

编辑

我最终得到了这样的东西:

def parse(path: String): Either[
  String,  // error
  AnyRef   // result
] = ?

def consistent(result: Either[String, AnyRef]): Either[
  String,  // error
  AnyRef   // result
] = ?

def conforms(result1: Either[String, AnyRef], result2: Either[String, AnyRef], 
  fullReport: List[Either[
    List[String],  // either list of errors 
    AnyRef         // or result
  ]]): List[Either[List[String], AnyRef]] = ?

( (parse("t1") :: Nil).map(consistent _), 
  (parse("t2") :: Nil).map(consistent _)
).zipped.foldLeft(List[Either[List[String], AnyRef]]())((fullReport, t1t2) =>
  conforms(t1t2._1, t1t2._2, fullReport))
点赞