这是我之前的问题的后续
假设我需要验证这样的 XML:
<a><a1>xxx<a1/><a2>yyy</a2><a3>zzz</a3></a>
我需要确保根元素有 labela
并且也有 children <a1>xxx</a1>
, <a2>yyy</a2>
,<a3>zzz</a3>
按此顺序。
我想List[String]
用来收集错误并定义一个函数来验证单个 XML 元素,如下所示:
type ValidateSingleElement = Elem => List[String]
现在我可以编写函数来验证给定 XML 元素的标签、文本和属性:
val label : String => ValidateSingleElement = ...
val text : String => ValidateSingleElement = ...
val attr : (String, String) => ValidateSingleElement = ...
我可以用|+|
因为ValidateSingleElement
是一个幺半群来组合这些函数。
val a1 = label("a1") |+| text("xxx") // validate both label and text
现在我需要一个函数来验证给定元素的子元素。为了编写这样一个函数,我需要另一个函数来验证一系列元素
val children: ValidateElements => ValidateSingleElement = ...
ValidateElements
定义如下:
type ValidateElements = List[Elem] => Writer[List[String], List[Elem]]
我在遍历元素序列时使用List[String]
and Writer
monad 来收集错误。
现在我可以编写一个函数来验证给定元素的子元素:
val children: ValidateElements => ValidateSingleElement =
validateElements => {e =>
val kids = e.child collect {case e:Elem => e}
val writer = validateElements(kids.toList)
writer.written
}
...并验证序列的第一个元素:
val child: ValidateSingleElement => ValidateElements = validate => {
_ match {
case e:es => Writer(validate(e), es)
case _ => Writer(List("Unexpected end of input"), Nil)
}
}
最后我可以重新定义ValidateElements
为Kleisli
type ErrorsWriter[A] = Writer[List[String], A]
type ValidateElements = Kliesli[ErrorsWriter, List[Elem], List[Elem]]
...并重新编写child
返回Kleisli
而不是函数。
鉴于两者child
,children
我可以编写a
- 从上面的 XML 验证函数:
val a1 = label("a1") |+| text("xxx")
val a2 = label("a2") |+| text("yyy")
val a3 = label("a3") |+| text("zzz")
val a = label("a") |+| children(child(a1) >=> child(a2) >=> child(a3))
是否有意义 ?您将如何纠正/扩展此设计?