( 後記 )
以下のコードで実行できることがわかりました。
【 わかったこと 】
- Refinedは、コンパイル時にオブジェクトの値制約が充足されているかどうかをチェックする。
- リテラル値(5, "abc", 'a'など)はコンパイルが行われる時点で、値が分かるので、依存型Refinedの値制約を帯びたオブジェクトの初期化宣言として受け入れられる。
- 変数x, yなどに格納(名前束縛)された値の中身は、コンパイル時に内容を(コンパイラが)判断できない。そのため、依存型Refinedの値制約を帯びたオブジェクトの初期化宣言として受け入れらない(エラーが変える)。
- RefineV()関数を変数x, yにかけると、上記が解決される。
- RefineV()関数を、Int型のオブジェクトに適用すると、Either型オブジェクトが出力される。
- Eitherオブジェクトから、Either.right.get関数で値を取り出す
- 取り出した値(Int型オブジェクトのリテラル値)を初期化変数として、依存型Refinedの値制約を帯びたオブジェクトを宣言する(val宣言またはvar宣言)
成功するコード
sbtConsole
scala> val positive: Int Refined Positive = refineV[Positive](x).right.get
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val positive: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive] = 3
scala> positive
val res35: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive] = 3
scala>
sbtConsole
scala> val temp = refineV[Positive](x).right.get
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val temp: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive] = 3
scala> temp
val res34: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive] = 3
scala> val positive: Int Refined Positive = temp
val positive: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive] = 3
scala> positive
val res35: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive] = 3
scala>
Int型のオブジェクトを格納(名前束縛)した変数だけでなく、String型を格納した変数や、List型を格納した変数を扱う場合も含めて、以下の記事で解説しています。
この記事はここから始まります
以下の方も同じ問題に直面している。
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
いるから。 PositiveタイプのValidate特性のインスタンスを見つけるのに役立つ人がいるかどうか疑問に思っていました>か?あるいは、私はそのようなインスタンスを自分で提供すべきですか?
- refinedのバージョン 0.9.27を読み込んでいます。
build.sbt
scalaVersion := "2.13.6"
libraryDependencies += "eu.timepit" %% "refined" % "0.9.27"
- sbt consoleでREPLを起動。
Terminal
% sbt console
WARNING: A terminally deprecated method in java.lang.System has been called
WARNING: System::setSecurityManager has been called by sbt.TrapExit$ (file:/Users/electron/.sbt/boot/scala-2.12.14/org.scala-sbt/sbt/1.5.5/run_2.12-1.5.5.jar)
WARNING: Please consider reporting this to the maintainers of sbt.TrapExit$
WARNING: System::setSecurityManager will be removed in a future release
[info] welcome to sbt 1.5.5 (Homebrew Java 17.0.1)
[info] loading project definition from /Users/electron/refined_trial/project
[info] loading settings for project refined_trial from build.sbt ...
[info] set current project to refined_trial (in build file:/Users/electron/refined_trial/)
[info] Starting scala interpreter...
Welcome to Scala 2.13.6 (OpenJDK 64-Bit Server VM, Java 17.0.1).
Type in expressions for evaluation. Or try :help.
scala>
sbtConsole
scala> import eu.timepit.refined._
import eu.timepit.refined._
scala> import eu.timepit.refined.auto._
import eu.timepit.refined.auto._
scala> import eu.timepit.refined.numeric._
import eu.timepit.refined.numeric._
scala> import eu.timepit.refined.api.{RefType, Refined}
import eu.timepit.refined.api.{RefType, Refined}
scala> import eu.timepit.refined.boolean._
import eu.timepit.refined.boolean._
scala> import eu.timepit.refined.char._
import eu.timepit.refined.char._
scala> import eu.timepit.refined.collection._
import eu.timepit.refined.collection._
scala> import eu.timepit.refined.generic._
import eu.timepit.refined.generic._
scala> import eu.timepit.refined.string._
import eu.timepit.refined.string._
scala> import shapeless.{ ::, HNil }
import shapeless.{$colon$colon, HNil}
scala>
refinedで型の値制約を定義
sbtConsole
scala> type ConditionedInt = Int Refined Interval.ClosedOpen[10000, 10000000]
type ConditionedInt
scala>
リテラル値による値束縛(代入)を伴うオブジェクト宣言はできる
sbtConsole
scala> val a: ConditionedInt = 100000
val a: ConditionedInt = 100000
scala> a
val res13: ConditionedInt = 100000
scala> val b: ConditionedInt = 100
^
error: Left predicate of (!(100 < 10000) && (100 < 10000000)) failed: Predicate (100 < 10000) did not fail.
scala>
別の変数の名前束縛(代入)伴うオブジェクト宣言はできなくなる
sbtConsole
scala> val john_tuple = ("John", 100000)
val john_tuple: (String, Int) = (John,100000)
cala> val (name, sales_volume) = john_tuple
val name: String = John
val sales_volume: Int = 100000
scala> name
val res11: String = John
scala> sales_volume
val res12: Int = 100000
scala>
- 以下がエラーになる
- リテラル値しかダメと言われる
errorメッセージcompile-time refinement only works with literals
sbtConsole
scala> val a: ConditionedInt = sales_volume
^
error: compile-time refinement only works with literals
scala>