在斯卡拉通用更新功能的工作,我需要創建一個產品類型&
代表一個複合值,例如:實現產品類型在斯卡拉在其部分
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