在斯卡拉通用更新功能的工作,我需要创建一个产品类型&
代表一个复合值,例如:实现产品类型在斯卡拉在其部分
val and: String & Int & User & ... = ???
即and
应该有一个String
部分和一个Int
部分和User
部分里面。这类似于斯卡拉with
关键字:
val and: String with Int with User with ... = ???
有这样的产品类型,我需要一种方法来,具有如下功能A => A
,它适用于某些产品的价值,并获得该产品回来改变A
一部分。这意味着产品中的每种类型都必须是唯一的 - 这是可以接受的。
一个重要的限制是,当将一个函数A => A
应用于产品时,我只知道该产品内部有A
,但没有关于其组成的其他类型的信息。但作为该函数的调用者,我将它传递给一个完整类型信息的产品,并希望将这个完整类型作为函数签名的一部分。
在伪代码:
def update[A, Rest](product: A & Rest, f: A => A): A & Rest
使用无形或其他深奥的东西是没有问题啊。我尝试使用HList
s,但它们是有序的,而像异构集合这样的东西更适合于表示A & Rest
部分。
UPDATE:
这里是低于机智加入读取支持,一些评论认为,解决从雷吉斯让 - 吉尔的回答了我的使用情况下,代码和改进类型安全:
object product {
/** Product of `left` and `right` values. */
case class &[L, R](left: L, right: R)
implicit class AndPimp[L](val left: L) extends AnyVal {
/** Make a product of `this` (as left) and `right`. */
def &[R](right: R): L & R = new &(left, right)
}
/* Updater. */
/** Product updater able to update value of type `A`. */
trait ProductUpdater[P, A] {
/** Update product value of type `A`.
* @return updated product */
def update(product: P, f: A ⇒ A): P
}
trait LowPriorityProductUpdater {
/** Non-product value updater. */
implicit def valueUpdater[A]: ProductUpdater[A, A] = new ProductUpdater[A, A] {
override def update(product: A, f: A ⇒ A): A = f(product)
}
}
object ProductUpdater extends LowPriorityProductUpdater {
/** Left-biased product value updater. */
implicit def leftProductUpdater[L, R, A](implicit leftUpdater: ProductUpdater[L, A]): ProductUpdater[L & R, A] =
new ProductUpdater[L & R, A] {
override def update(product: L & R, f: A ⇒ A): L & R =
leftUpdater.update(product.left, f) & product.right
}
/** Right-biased product value updater. */
implicit def rightProductUpdater[L, R, A](implicit rightUpdater: ProductUpdater[R, A]): ProductUpdater[L & R, A] =
new ProductUpdater[L & R, A] {
override def update(product: L & R, f: A ⇒ A): L & R =
product.left & rightUpdater.update(product.right, f)
}
}
/** Update product value of type `A` with function `f`.
* Won't compile if product contains multiple `A` values.
* @return updated product */
def update[P, A](product: P)(f: A ⇒ A)(implicit updater: ProductUpdater[P, A]): P =
updater.update(product, f)
/* Reader. */
/** Product reader able to read value of type `A`. */
trait ProductReader[P, A] {
/** Read product value of type `A`. */
def read(product: P): A
}
trait LowPriorityProductReader {
/** Non-product value reader. */
implicit def valueReader[A]: ProductReader[A, A] = new ProductReader[A, A] {
override def read(product: A): A = product
}
}
object ProductReader extends LowPriorityProductReader {
/** Left-biased product value reader. */
implicit def leftProductReader[L, R, A](implicit leftReader: ProductReader[L, A]): ProductReader[L & R, A] =
new ProductReader[L & R, A] {
override def read(product: L & R): A =
leftReader.read(product.left)
}
/** Right-biased product value reader. */
implicit def rightProductReader[L, R, A](implicit rightReader: ProductReader[R, A]): ProductReader[L & R, A] =
new ProductReader[L & R, A] {
override def read(product: L & R): A =
rightReader.read(product.right)
}
}
/** Read product value of type `A`.
* Won't compile if product contains multiple `A` values.
* @return value of type `A` */
def read[P, A](product: P)(implicit productReader: ProductReader[P, A]): A =
productReader.read(product)
// let's test it
val p = 1 & 2.0 & "three"
read[Int & Double & String, Int](p) // 1
read[Int & Double & String, Double](p) // 2.0
read[Int & Double & String, String](p) // three
update[Int & Double & String, Int](p)(_ * 2) // 2 & 2.0 & three
update[Int & Double & String, Double](p)(_ * 2) // 1 & 4.0 & three
update[Int & Double & String, String](p)(_ * 2) // 1 & 2.0 & threethree
}
关于'HList'是ordere D:这是无法修复的。虽然你可以定义方法/类型类来比较两种产品,并告诉你它们是否具有相同的类型,而不管顺序如何,但当谈到类型系统本身时,你是不幸的。你可以尝试所有的魔法,你永远不会让编译器认为'&[Int,String]'和'&[String,Int]'是一样的(这不足以实现一个完全接管的编译器插件类型检查这些类型,如果甚至可能的话)。 –
@RégisJean-Gilles,明白了,谢谢。 – Tvaroh