英文:
Define new type whose domain is subset of another type in Scala
问题
使用偶数的示例,我想定义一个名为“Even”的类型,其域是偶数整数使用函数
val isEven(i: Int): Boolean = i % 2 == 0
如何在Scala 3中使用不透明关键字实现这一点...
opaque type Even = ??? // use Int and filter using isEven
或者如果那行不通,
type Even = ???
理念是使用函数作为构建新类型的基石,而不是通过使用newtype(如scala-even-type-number)或使用Refined Types来使事情复杂化。
英文:
Using the example of even numbers, I would like to define the Even type whose domain is even integers using the function
val isEven(i: Int): Boolean = i % 2 == 0
How would I do this in Scala 3 using the opaque keyword...
opaque type Even = ??? // use Int and filter using isEven
or if that does not work,
type Even = ???
The rationale is to use functions as a building block to create new types, rather that complicating matters by using newtype as scala-even-type-number or using Refined Types
答案1
得分: 4
透明类型 Evens:
不透明类型 Even = Int
对象 Even:
def apply(i: Int): Even = if i % 2 == 0 then i else sys.error(s"$i 是奇数")
def unsafe(i: Int): Even = i
def safe(i: Int): Option[Even] = Option.when(i % 2 == 0)(i)
扩展 (x: Even):
def toInt: Int = x
def +(y: Even): Even = x + y
def *(y: Int): Even = x * y
def half: Int = x / 2
end Evens
import Evens.*
// val x: Even = 2 // 无法编译
val x: Even = Even(2)
// val x: Even = Even(3) // 运行时异常: 3 是奇数
https://docs.scala-lang.org/scala3/book/types-opaque-types.html
https://docs.scala-lang.org/scala3/reference/other-new-features/opaques.html
如果想让 Even(3)
在编译时而非运行时失败,请用以下一种实现替换 def apply(i: Int): Even = ...
import scala.compiletime.{error, erasedValue, constValue, codeOf, summonFrom}
import scala.compiletime.ops.int.%
import scala.compiletime.ops.any.{==, ToString}
inline def apply[I <: Int with Singleton](inline i: I): Even =
inline erasedValue[I % 2] match
case _: 0 => i
case _ => error(codeOf(i) + " 是奇数")
inline def apply[I <: Int with Singleton](inline i: I): Even =
inline if constValue[I % 2] == 0 then i else error(codeOf(i) + " 是奇数")
inline def apply[I <: Int with Singleton](inline i: I): Even =
inline erasedValue[I % 2 == 0] match
case _: true => i
case _ => error(constValue[ToString[I]] + " 是奇数")
inline def apply[I <: Int with Singleton](inline i: I): Even =
summonFrom {
case _: (I % 2 =:= 0) => i
case _ => error(constValue[ToString[I]] + " 是奇数")
}
inline def apply(inline i: Int): Even =
inline if i % 2 == 0 then i else error(codeOf(i) + " 是奇数")
https://docs.scala-lang.org/scala3/reference/metaprogramming/inline.html
https://docs.scala-lang.org/scala3/reference/metaprogramming/compiletime-ops.html
英文:
Something like the following:
object Evens:
opaque type Even = Int
object Even:
def apply(i: Int): Even = if i % 2 == 0 then i else sys.error(s"$i is odd")
def unsafe(i: Int): Even = i
def safe(i: Int): Option[Even] = Option.when(i % 2 == 0)(i)
extension (x: Even)
def toInt: Int = x
def +(y: Even): Even = x + y
def *(y: Int): Even = x * y
def half: Int = x / 2
end Evens
import Evens.*
// val x: Even = 2 // doesn't compile
val x: Even = Even(2)
// val x: Even = Even(3) // RuntimeException: 3 is odd
https://docs.scala-lang.org/scala3/book/types-opaque-types.html
https://docs.scala-lang.org/scala3/reference/other-new-features/opaques.html
If you'd like Even(3)
to fail at compile time rather than runtime then replace def apply(i: Int): Even = ...
with one of the following implementations
import scala.compiletime.{error, erasedValue, constValue, codeOf, summonFrom}
import scala.compiletime.ops.int.%
import scala.compiletime.ops.any.{==, ToString}
inline def apply[I <: Int with Singleton](inline i: I): Even =
inline erasedValue[I % 2] match
case _: 0 => i
case _ => error(codeOf(i) + " is odd")
inline def apply[I <: Int with Singleton](inline i: I): Even =
inline if constValue[I % 2] == 0 then i else error(codeOf(i) + " is odd")
inline def apply[I <: Int with Singleton](inline i: I): Even =
inline erasedValue[I % 2 == 0] match
case _: true => i
case _ => error(constValue[ToString[I]] + " is odd")
inline def apply[I <: Int with Singleton](inline i: I): Even =
summonFrom {
case _: (I % 2 =:= 0) => i
case _ => error(constValue[ToString[I]] + " is odd")
}
inline def apply(inline i: Int): Even =
inline if i % 2 == 0 then i else error(codeOf(i) + " is odd")
https://docs.scala-lang.org/scala3/reference/metaprogramming/inline.html
https://docs.scala-lang.org/scala3/reference/metaprogramming/compiletime-ops.html
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论