定义一个新类型,其域是另一类型的子集在Scala中

huangapple go评论122阅读模式
英文:

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 或者如果那行不通,

  1. 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,

  1. 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

  1. 透明类型 Evens:
  2. 不透明类型 Even = Int
  3. 对象 Even:
  4. def apply(i: Int): Even = if i % 2 == 0 then i else sys.error(s"$i 是奇数")
  5. def unsafe(i: Int): Even = i
  6. def safe(i: Int): Option[Even] = Option.when(i % 2 == 0)(i)
  7. 扩展 (x: Even):
  8. def toInt: Int = x
  9. def +(y: Even): Even = x + y
  10. def *(y: Int): Even = x * y
  11. def half: Int = x / 2
  12. end Evens
  13. import Evens.*
  14. // val x: Even = 2 // 无法编译
  15. val x: Even = Even(2)
  16. // 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 = ...

  1. import scala.compiletime.{error, erasedValue, constValue, codeOf, summonFrom}
  2. import scala.compiletime.ops.int.%
  3. import scala.compiletime.ops.any.{==, ToString}
  4. inline def apply[I <: Int with Singleton](inline i: I): Even =
  5. inline erasedValue[I % 2] match
  6. case _: 0 => i
  7. case _ => error(codeOf(i) + " 是奇数")
  1. inline def apply[I <: Int with Singleton](inline i: I): Even =
  2. inline if constValue[I % 2] == 0 then i else error(codeOf(i) + " 是奇数")
  1. inline def apply[I <: Int with Singleton](inline i: I): Even =
  2. inline erasedValue[I % 2 == 0] match
  3. case _: true => i
  4. case _ => error(constValue[ToString[I]] + " 是奇数")
  1. inline def apply[I <: Int with Singleton](inline i: I): Even =
  2. summonFrom {
  3. case _: (I % 2 =:= 0) => i
  4. case _ => error(constValue[ToString[I]] + " 是奇数")
  5. }
  1. inline def apply(inline i: Int): Even =
  2. 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:

  1. object Evens:
  2. opaque type Even = Int
  3. object Even:
  4. def apply(i: Int): Even = if i % 2 == 0 then i else sys.error(s&quot;$i is odd&quot;)
  5. def unsafe(i: Int): Even = i
  6. def safe(i: Int): Option[Even] = Option.when(i % 2 == 0)(i)
  7. extension (x: Even)
  8. def toInt: Int = x
  9. def +(y: Even): Even = x + y
  10. def *(y: Int): Even = x * y
  11. def half: Int = x / 2
  12. end Evens
  13. import Evens.*
  14. // val x: Even = 2 // doesn&#39;t compile
  15. val x: Even = Even(2)
  16. // 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

  1. import scala.compiletime.{error, erasedValue, constValue, codeOf, summonFrom}
  2. import scala.compiletime.ops.int.%
  3. import scala.compiletime.ops.any.{==, ToString}
  4. inline def apply[I &lt;: Int with Singleton](inline i: I): Even =
  5. inline erasedValue[I % 2] match
  6. case _: 0 =&gt; i
  7. case _ =&gt; error(codeOf(i) + &quot; is odd&quot;)
  1. inline def apply[I &lt;: Int with Singleton](inline i: I): Even =
  2. inline if constValue[I % 2] == 0 then i else error(codeOf(i) + &quot; is odd&quot;)
  1. inline def apply[I &lt;: Int with Singleton](inline i: I): Even =
  2. inline erasedValue[I % 2 == 0] match
  3. case _: true =&gt; i
  4. case _ =&gt; error(constValue[ToString[I]] + &quot; is odd&quot;)
  1. inline def apply[I &lt;: Int with Singleton](inline i: I): Even =
  2. summonFrom {
  3. case _: (I % 2 =:= 0) =&gt; i
  4. case _ =&gt; error(constValue[ToString[I]] + &quot; is odd&quot;)
  5. }
  1. inline def apply(inline i: Int): Even =
  2. inline if i % 2 == 0 then i else error(codeOf(i) + &quot; is odd&quot;)

https://docs.scala-lang.org/scala3/reference/metaprogramming/inline.html

https://docs.scala-lang.org/scala3/reference/metaprogramming/compiletime-ops.html

huangapple
  • 本文由 发表于 2023年4月4日 07:23:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/75924406.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定