是的,我已經檢查了標題非常相似的問題,但是給出的答案對我的幫助不如我剛接觸 Scala 并且無法理解它。
我正在撰寫一些檢查卡片串列并根據串列結果回傳分數的函式。從技術上講,它會檢查一組卡片串列,但是出于這個問題的目的,我正在簡化代碼。
現在,我希望這些函式可以擴展到不同型別的評分。例如,如果所有的牌都是紅心,那么我們可以給他們 1 分。但是,在另一個規則集中,它可能會給出 3 分。
我有一個積分包裝,可以轉化為最終分數。這意味著一種型別的分數可能會轉化為與另一種型別的分數不同的最終分數。這里的目的是允許您自定義計分并以稍微不同的方式玩紙牌游戲。
您將在下面的示例代碼中看到,但我最終在我的方法宣告中得到了很多重復,即不得不[T <: HandPoints[T]]一遍又一遍地撰寫。
所有def方法都寫在一個 中object,所以我不能將型別引數添加到類中。
我想可能有一個很好的解決方案可以在類之外提取這些方法,但我希望檢查卡片的方法不會重復,所以讓它們在object
這是 HandPoints 特征:
trait HandPoints[T] {
def toHandScore: HandScore
def zero: T
def add(that: T): T
}
case class RegularPoint(points: Int) extends HandPoints[RegularPoint] {
override def toHandScore: HandScore = HandScore(points)
override def zero: RegularPoint = RegularPoint(0)
override def add(that: RegularPoint): RegularPoint = RegularPoint(points that.points)
}
case class DoublingPoints(points: Int) extends HandPoints[DoublingPoints] {
override def toHandScore: HandScore = HandScore(points*2)
override def zero: DoublingPoints = DoublingPoints(0)
override def add(that: DoublingPoints): DoublingPoints = DoublingPoints(points that.points)
}
case class HandScore(score: Int) {
}
這是我為評估卡片而撰寫的函式
trait Card {
def getValue: Int
def getSuit: String
}
def scored[T <: HandPoints[T]](score: T)(boolean: Boolean): T = {
if (boolean) score else score.zero
}
def isAllEvens[T <: HandPoints[T]](score: T)(cards: List[Card]): T = {
scored(score) {
cards.forall(_.getValue % 2 == 0)
}
}
def isAllReds[T <: HandPoints[T]](score: T)(cards: List[Card]): T = {
scored(score) {
cards.forall(List("HEARTS", "DIAMONDS").contains(_))
}
}
def isAllNoDuplicates[T <: HandPoints[T]](score: T)(cards: List[Card]): T = {
scored(score) {
cards.distinct == cards
}
}
val regularGameCriteria: List[List[Card] => RegularPoint] = List(
isAllEvens(RegularPoint(1)),
isAllReds(RegularPoint(3)),
isAllNoDuplicates(RegularPoint(5))
)
val beginnerGameCriteria: List[List[Card] => RegularPoint] = List(
isAllEvens(RegularPoint(1)),
isAllReds(RegularPoint(1)),
isAllNoDuplicates(RegularPoint(1))
)
val superGameCriteria: List[List[Card] => DoublingPoints] = List(
isAllEvens(DoublingPoints(1)),
isAllReds(DoublingPoints(3)),
isAllNoDuplicates(DoublingPoints(5))
)
def countScore[T <: HandPoints[T]](scoreList: List[List[Card] => T])(melds: List[Card]): T = {
scoreList.map(f => f(melds)).reduce((a, b) => a.add(b))
}
def regularGameScore(cards: List[Card]): RegularPoint = {
countScore(regularGameCriteria)(cards)
}
def beginnerGameScore(cards: List[Card]): RegularPoint = {
countScore(beginnerGameCriteria)(cards)
}
def superGameScore(cards: List[Card]): DoublingPoints = {
countScore(superGameCriteria)(cards)
}
uj5u.com熱心網友回復:
首先,您可以查看 F 有界多型性如何被臨時多型性(型別類)替換:
https://tpolecat.github.io/2015/04/29/f-bounds.html
其次,不同方法的界限[T <: HandPoints[T]]其實并不是代碼重復。不同T的方法不同的是不同的型別引數。你只是用同一個字母給他們打電話。一個型別引數的邊界不限制另一個型別引數。
我很好奇你為什么考慮使用[T <: HandPoints[T]]不同的方法而不是(score: T)or的代碼重復(cards: List[Card])。我猜是因為大多數人考慮術語,認為型別不太重要。
第三,您應該開始探索 OOP(或帶有型別類或它們的混合的 FP),即將您的方法組織成具有某些行為的類/物件(或型別類)。現在一堆(靜態)方法看起來像程序編程。
例如,首先我們可以引入兩個類HandPointsHandler和Criteria(你可以選擇更好的名字):
case class HandScore(score: Int)
trait HandPoints[T] {
def toHandScore: HandScore
def zero: T
def add(that: T): T
}
case class RegularPoint(points: Int) extends HandPoints[RegularPoint] {
override def toHandScore: HandScore = HandScore(points)
override def zero: RegularPoint = RegularPoint(0)
override def add(that: RegularPoint): RegularPoint = RegularPoint(points that.points)
}
case class DoublingPoints(points: Int) extends HandPoints[DoublingPoints] {
override def toHandScore: HandScore = HandScore(points*2)
override def zero: DoublingPoints = DoublingPoints(0)
override def add(that: DoublingPoints): DoublingPoints = DoublingPoints(points that.points)
}
trait Card {
def getValue: Int
def getSuit: String
}
// new class
class HandPointsHandler[T <: HandPoints[T]] {
def scored(score: T)(boolean: Boolean): T =
if (boolean) score else score.zero
def isAllEvens(score: T)(cards: List[Card]): T =
scored(score) {
cards.forall(_.getValue % 2 == 0)
}
def isAllReds(score: T)(cards: List[Card]): T =
scored(score) {
cards.forall(List("HEARTS", "DIAMONDS").contains)
}
def isAllNoDuplicates(score: T)(cards: List[Card]): T =
scored(score) {
cards.distinct == cards
}
def countScore(scoreList: List[List[Card] => T])(melds: List[Card]): T =
scoreList.map(_.apply(melds)).reduce(_ add _)
}
// new class
class Criteria[T <: HandPoints[T]](handler: HandPointsHandler[T], points: List[T]) {
val gameCriteria: List[List[Card] => T] = {
List(
handler.isAllEvens _,
handler.isAllReds _,
handler.isAllNoDuplicates _
).zip(points).map { case (f, point) => f(point) }
}
}
val points135 = List(1, 3, 5)
val points111 = List(1, 1, 1)
val regularPointsHandler = new HandPointsHandler[RegularPoint]
val regularGameCriteria: List[List[Card] => RegularPoint] =
new Criteria[RegularPoint](regularPointsHandler, points135.map(RegularPoint)).gameCriteria
val beginnerGameCriteria: List[List[Card] => RegularPoint] =
new Criteria[RegularPoint](regularPointsHandler, points111.map(RegularPoint)).gameCriteria
val doublingPointsHandler = new HandPointsHandler[DoublingPoints]
val superGameCriteria: List[List[Card] => DoublingPoints] =
new Criteria[DoublingPoints](doublingPointsHandler, points135.map(DoublingPoints)).gameCriteria
def regularGameScore(cards: List[Card]): RegularPoint =
regularPointsHandler.countScore(regularGameCriteria)(cards)
def beginnerGameScore(cards: List[Card]): RegularPoint =
regularPointsHandler.countScore(beginnerGameCriteria)(cards)
def superGameScore(cards: List[Card]): DoublingPoints =
doublingPointsHandler.countScore(superGameCriteria)(cards)
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/511726.html
