Scala:精炼的代数数据类型
Scala: Refined Algebraic Data Types
o/
这可能是一个相当有趣的问题,并且可能会激发您的一些创造力。
我想以我可以的方式为货币建模:
- 模式匹配类型(=> 代数数据类型)
- 在其中存储一个数字金额
- 使用 refined type 将值限制为例如正值,例如
val amount: Float Refined Positive
- 有一个像 "USD" 这样的预定义且不可变的三字符货币代码
在一个实现中完成其中的一个子集很容易,但我发现创建一个允许类似以下内容的类型非常困难:
def doSomething(currency: Currency): Unit {
currency match {
case BITCOIN => println("Oh, a cryptocurrency! And it is ${currency.amount} ${currency.code}!"
case EURO => println("So we are from Europe, eh?")
}
}
doSomething(new Currency.BITCOIN(123f)) // yielding "Oh, a cryptocurrency! And it is 123 BTC!"
val euro = new Currency.EURO(-42f) // compile error
我希望我表达清楚了我的意图。如果有图书馆这样做,我很高兴有人指出它,尽管我希望自己能从思考中学到一些东西。
你的意思是这样的吗?
import eu.timepit.refined.api.Refined
import eu.timepit.refined.auto._
import eu.timepit.refined.numeric.NonNegative
import eu.timepit.refined.string.MatchesRegex
sealed trait Currency extends Product with Serializable {
def amount: Currency.Amount
def code: Currency.Code
}
object Currency {
type Amount = BigDecimal Refined NonNegative
type Code = String Refined MatchesRegex["[A-Z]{3}"]
final case class Euro(amount: Amount) extends Currency {
override final val code: Code = "EUR"
}
final case class Dollar(amount: Amount) extends Currency {
override final val code: Code = "USD"
}
}
def doSomething(currency: Currency): Unit =
currency match {
case Currency.Euro(amount) => println(s"Euro: € ${amount}")
case _ => println(s"Somenthing else with code ${currency.code} and amount ${currency.amount}")
}
这个有效:
doSomething(Currency.Dollar(BigDecimal(10)))
// Somenthing else with code USD and amount 10
o/
这可能是一个相当有趣的问题,并且可能会激发您的一些创造力。
我想以我可以的方式为货币建模:
- 模式匹配类型(=> 代数数据类型)
- 在其中存储一个数字金额
- 使用 refined type 将值限制为例如正值,例如
val amount: Float Refined Positive
- 有一个像 "USD" 这样的预定义且不可变的三字符货币代码
在一个实现中完成其中的一个子集很容易,但我发现创建一个允许类似以下内容的类型非常困难:
def doSomething(currency: Currency): Unit {
currency match {
case BITCOIN => println("Oh, a cryptocurrency! And it is ${currency.amount} ${currency.code}!"
case EURO => println("So we are from Europe, eh?")
}
}
doSomething(new Currency.BITCOIN(123f)) // yielding "Oh, a cryptocurrency! And it is 123 BTC!"
val euro = new Currency.EURO(-42f) // compile error
我希望我表达清楚了我的意图。如果有图书馆这样做,我很高兴有人指出它,尽管我希望自己能从思考中学到一些东西。
你的意思是这样的吗?
import eu.timepit.refined.api.Refined
import eu.timepit.refined.auto._
import eu.timepit.refined.numeric.NonNegative
import eu.timepit.refined.string.MatchesRegex
sealed trait Currency extends Product with Serializable {
def amount: Currency.Amount
def code: Currency.Code
}
object Currency {
type Amount = BigDecimal Refined NonNegative
type Code = String Refined MatchesRegex["[A-Z]{3}"]
final case class Euro(amount: Amount) extends Currency {
override final val code: Code = "EUR"
}
final case class Dollar(amount: Amount) extends Currency {
override final val code: Code = "USD"
}
}
def doSomething(currency: Currency): Unit =
currency match {
case Currency.Euro(amount) => println(s"Euro: € ${amount}")
case _ => println(s"Somenthing else with code ${currency.code} and amount ${currency.amount}")
}
这个有效:
doSomething(Currency.Dollar(BigDecimal(10)))
// Somenthing else with code USD and amount 10