我有这样的工作流程:
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))