Refinedで定義された値制約が付いたオブジェクトは、数値リテラル(1, 175など)や文字列リテラル("abc"など)を与えると、オブジェクトを初期化宣言させることができます。
他方で、すでに定義済みの変数(x, y, customer_name, sales_volumeなど)で初期化宣言をしようとすると、「リテラル値でないと受付けられません」というエラーメッセージが吐かれてしまいます。
そのため、関数の引数にRefined値制約を付ける場合、その引数にリテラル値ではない「変数x」が渡された場合は、エラーが発生してしまうことになります。
そうした事例が、以下のウェブページで報告されています。
package xxx import eu.timepit.refined._ import eu.timepit.refined.api.{Refined, Validate} import eu.timepit.refined.auto._ import eu.timepit.refined.numeric._ import eu.timepit.refined.api.Refined import eu.timepit.refined.numeric.Interval object Lala { type X = Integer Refined Positive def lala(x: Int): Unit = { val lala: X = refineV[X](x) } }
、私は、このエラーメッセージが表示されます:ポジ型のための検証の実装が欠落しているようだ
Error:(13, 29) could not find implicit value for parameter v: >eu.timepit.refined.api.Validate[Int,xxx.Lala.X] val lala: X = refineVX Error:(13, 29) not enough arguments for method apply: (implicit v: >eu.timepit.refined.api.Validate[Int,xxx.Lala.X])Either[String,eu.timepit.refined.api.R>efined[Int,xxx.Lala.X]] in class RefinePartiallyApplied. Unspecified value parameter >v. val lala: X = refineVX
この関数は、以下のように定義すると、引数として、リテラル値の整数が渡された場合も、変数に格納(名前束縛)された整数が渡された場合も、値検査を行った上で、正常に動作します。
sbtConsole
scala> type X = Integer Refined Positive
type X
scala>
scala> def lala(x: Int):Unit = {
| val lala: X = refineV[Positive](x).right.get
| println(x)
| }
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
def lala(x: Int): Unit
scala>
sbtConsole
scala> lala(3)
3
scala> val sample_number = 7
val sample_number: Int = 7
scala> lala(sample_number)
7
scala>
- 値制約条件__X__を充足しない整数(0と負整数)が渡された場合は、ちゃんとエラーになります。
- ここは、errorを発生させずに、Either型かOption側で対応させたいところではあります。
sbtConsole
scala> lala(-10)
java.util.NoSuchElementException: Either.right.get on Left
at scala.util.Either$RightProjection.get(Either.scala:696)
at lala(<console>:2)
... 35 elided
scala> val negative_number = -7
val negative_number: Int = -7
scala> lala(negative_number)
java.util.NoSuchElementException: Either.right.get on Left
at scala.util.Either$RightProjection.get(Either.scala:696)
at lala(<console>:2)
... 35 elided
scala> val zero_number = 0
val zero_number: Int = 0
scala> lala(zero_number)
java.util.NoSuchElementException: Either.right.get on Left
at scala.util.Either$RightProjection.get(Either.scala:696)
at lala(<console>:2)
... 35 elided
scala>
上記のコードの書き方について、背景は以下の記事で解説しています。