让我们考虑一个分类问题:
object Classify extends App {
type Tag = String
type Classifier[A] = A => Set[Tag]
case class Model(a: Int, b: String, c: String, d: String)
def aClassifier : Classifier[Int] = _ => Set("A", "a")
def bClassifier : Classifier[String] = _ => Set("B")
def cClassifier : Classifier[String] = _ => Set("C")
def modelClassifier : Classifier[Model] = {
m => aClassifier(m.a) ++ bClassifier(m.b) ++ cClassifier(m.c)
}
println(modelClassifier(Model(1,"b", "c", "d")))
}
使用scalaz实现modelClassifier
是否有更聪明的方法?
答案 0 :(得分:1)
scalaz库没有按设计进行任何宏case class
内省,但shapeless有
考虑这样的定义:
import shapeless._
import shapeless.tag._
import shapeless.labelled._
trait Omit
val omit = tag[Omit]
case class Model(a: Int, b: String, c: String, d: String @@ Omit)
object classifiers extends Poly1 {
implicit def stringClassifier[K <: Symbol](implicit witness: Witness.Aux[K]) =
at[FieldType[K, String]](value => Set(witness.value.name.toUpperCase))
implicit def intClassifier[K <: Symbol](implicit witness: Witness.Aux[K]) =
at[FieldType[K, Int]](value => {
val name = witness.value.name
Set(name.toUpperCase, name.toLowerCase)
})
implicit def omitClassifier[K, T] =
at[FieldType[K, T @@ Omit]](_ => Set.empty[String])
}
现在您的modelClassifier
可以完成:
def modelClassifier: Classifier[Model] =
m => LabelledGeneric[Model].to(m).map(classifiers).toList.reduce(_ union _)
你可以通过
查看println(modelClassifier(Model(1, "b", "c", omit("d"))))
请注意,Type @@ Tag
是Type
的子类型,因此model.d
仍可用作String
无处不在
答案 1 :(得分:0)
作为一个想法,请考虑以下代码:
for (i <- 0 until model.productArity) yield {
val fieldValue = model.productElement(i)
fieldValue match {
case x: Int => //use integer classifier
case s: String => //use string classifier
case _ =>
}
}
答案 2 :(得分:0)
您打算如何区分bClassifier
和cClassifier
?按名字?按照声明的顺序?这听起来不是很聪明&#34;或者可靠。请考虑明确编码您的意图。这样的事情,也许是:
case class Classifiable[T](data: T, classifier: Classifier[T])
object Classifiable {
def Null[T](data: T) = Classifiable(data, _ => Nil)
}
case class Model(a: Classifiable[Int], b: Classifiable[String], c: Classifiable[String], d: Classifiable[String])
object Model {
def apply(a: Int, b: String, c: String, d: String) =
Model(
Classifiable(a, aClassifier),
Classifiable(b, bClassifier),
Classifiable(c, cClassifier),
Classifiable.Null(d)
)
}
def modelClassifier(m: Model) = m
.productIterator
.collect { case x: Classifiable[_] =>
x.classifier()(x)
}
.reduce(_ ++ _)
println(modelClassifier(Model(1,"b", "c", "d")))