2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Scala】依存型の値制約付きのオブジェクトを、別の定義済み変数を代入して初期化宣言するコード〜 変数.RefinedV.right.get

Last updated at Posted at 2021-11-09

Refinedの値制約付きのオブジェクトは、数値リテラル(1, 175など)や文字列リテラル("abc"など)を与えると、初期化宣言出来ます。

他方で、すでに定義済みの変数(x, y, customer_name, sales_volumeなど)で初期化宣言をしようとすると、「リテラル値でないと受付けられません」というエラーメッセージが吐かれてしまいます。

すでに定義済みの変数(x, y, customer_name, sales_volumeなど)を用いて、Refinedの値制約付きのオブジェクトを初期化宣言するためには、次のいずれかのコードが必要になります。

  • RefinedV(定義済みの変数オブジェクト)
  • RefinedV(定義済みの変数オブジェクト).right.get

後者のコードは、refineV(定義済みの変数オブジェクト)の返り値(出力結果)がEither[失敗メッセージ, 成功した計算結果]である場合に必要となります。その場合に、RefinedV(定義済みの変数オブジェクト)だけを実行すると、以下のようなエラーが返ります。

エラーメッセージ
   error: polymorphic expression cannot be instantiated to expected type;
    found   : [P]Either[String,eu.timepit.refined.api.Refined[Int,P]]
    required: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive]
       (which expands to)  eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Greater[shapeless._0]]

求められているのはEither型ではなく、Either型のRightに格納されている、入力値の値(定義済みの変数)であると書かれています。

Either型のRightに格納されている、入力値を取り出すために、Eigher.right.getを実行する必要があります。

関数を作成するとき、受容する引数の型シグネチャに、Refinedで定義した値制約をtypeキーワードで命名した型名をつける場合があります。その関数には引数として、リテラル値でなく、変数(x, y, customer_name, sales_volumeなど)が入力される可能性があります。その場合、上記のコードを手当てしておく必要があります。

次の実行結果で見られる通り、refineVは、リテラル値を受け取った場合も、変数を受け取った場合も、どちら動作します。

Int型を受け取る関数の場合

__変数x__が渡された場合も、__リテラル値3__が渡された場合も、等しく正常に動作します。

sbtConsole
scala> val x = 10
val x: Int = 10

scala> x
val res85: Int = 10

scala> refineV[Positive](x).right.get
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val res86: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive] = 10

scala> refineV[Positive](3).right.get
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val res87: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive] = 3

scala>

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] = 10

scala> val positive: Int Refined Positive = refineV[Positive](3).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> 

String型を受け取る関数の場合

__変数x__が渡された場合も、__リテラル値"hogefuga"__が渡された場合も、等しく正常に動作します。

sbtConsole
scala> val x  = "hogefuga"
val x: String = hogefuga

scala>

scala> refineV[StartsWith["h"]](x).right.get
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val res88: eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.StartsWith["h"]] = hogefuga

scala> refineV[StartsWith["h"]]("hogefuga").right.get
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val res89: eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.StartsWith["h"]] = hogefuga

scala> 

scala> val startsWithHoge2: String Refined StartsWith["h"] = refineV[StartsWith["h"]](x).right.get
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val startsWithHoge2: eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.StartsWith["h"]] = hogefuga

scala> val startsWithHoge2: String Refined StartsWith["h"] = refineV[StartsWith["h"]]("hogefuga").right.get
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val startsWithHoge2: eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.StartsWith["h"]] = hogefuga

scala> 

scala> val startsWithHoge: String Refined StartsWith[W.`"hoge"`.T] = refineV[StartsWith["hoge"]](x).right.get
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val startsWithHoge: eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.StartsWith[String("hoge")]] = hogefuga

scala> val startsWithHoge2: String Refined StartsWith[W.`"hoge"`.T] = refineV[StartsWith["hoge"]]("hogefuge").right.get
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val startsWithHoge2: eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.StartsWith[String("hoge")]] = hogefuge

scala> 

以下のウェブページでは、上記のコードが必要となる事例が報告されています。

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> 

( 参考にしたウェブページ )

リテラルでない値についてはコンパイル時に値の性質がわからないため、自動でRefineされた型の値に変換することはできません。 このような場合にはrefineVを使用します。

Either型のオブジェクトを格納するコンテナオブジェクトList型を扱う場合

最初の例として、List[String]型__のオブジェクトに、Refined NonEmptyという値制約__を付加したクラスの型を定義します。先ほどリンクを貼った参考ウェブページに掲載されているコードを実行してみます。

定義した型に、typeキーワード__で、NonEmpty__というエイリアスを付けます。

sbtConsole
scala> type NonEmptyCollection = Seq[String] Refined NonEmpty
type NonEmptyCollection

scala>

次に、valキーワードで不変型のオブジェクト__string__を定義します。
このオブジェクトは、"hoge", "fuga", "tom"という3つのString型オブジェクトを要素として持ちます。

sbtConsole
scala> val strings = List("hoge", "fuga", "tom")
val strings: List[String] = List(hoge, fuga, tom)

定義した変数__stringsで、*Either[String, NonEmptyCollection]*型__のオブジェクトをvalキーワードで定義すると、エラーが返されます。

sbtConsole
scala> val nonEmpty2: Either[String, NonEmptyCollection] = strings
                                                           ^
       error: type mismatch;
        found   : List[String]
        required: Either[String,NonEmptyCollection]
           (which expands to)  Either[String,eu.timepit.refined.api.Refined[Seq[String],eu.timepit.refined.boolean.Not[eu.timepit.refined.collection.Empty]]]

scala> 

*Either[String,NonEmptyCollection]*型__が必要なのに、*List[String]*型__が渡されたと文句を言われました。

refineV(strings)を値束縛すると、エラーを吐くことなく成功しました。

sbtConsole
scala> val nonEmpty: Either[String, NonEmptyCollection] = refineV(strings)
val nonEmpty: Either[String,NonEmptyCollection] = Right(List(hoge, fuga, tom))

scala>

-nonEmptyには意図した通りに、値が格納(名前束縛)されました。

sbtConsole
scala> nonEmpty
val res19: Either[String,NonEmptyCollection] = Right(List(hoge, fuga, tom))

参考ウェブページにある次のコードも、エラーが出ずに実行できます。

sbtConsole
scala> type ContainsPositive = Seq[Int] Refined Exists[Positive]
type ContainsPositive

scala> val numbers = List(1, 3 ,5)
val numbers: List[Int] = List(1, 3, 5)

scala> val containsPositive: Either[String, ContainsPositive] = refineV(numbers) 
val containsPositive: Either[String,ContainsPositive] = Right(List(1, 3, 5))

scala> 

これも、__numbers__をそのまま与えると、エラーになります。

sbtConsole
scala> val containsPositive: Either[String, ContainsPositive] = numbers
                                                                ^
       error: type mismatch;
        found   : List[Int]
        required: Either[String,ContainsPositive]
           (which expands to)  Either[String,eu.timepit.refined.api.Refined[Seq[Int],eu.timepit.refined.boolean.Not[eu.timepit.refined.collection.Forall[eu.timepit.refined.boolean.Not[eu.timepit.refined.numeric.Greater[shapeless._0]]]]]]

scala> 

Int側を扱う場合

Int型の値に束縛(が代入)された変数については、参考ウェブページでは、サンプルコードが掲載されていません。

そこでこの記事の中で、Int型のリテラル値(数字、数値)を格納した変数を扱う場合を試してみます。

Int側をrefineV()関数に入力すると、Either型が返される。

そこで、Either型から入力したInt型オブジェクトを取り出すために、Either.right.get()関数を実行するコードを1行追加する必要があります。

  • 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> 

数値(Integerオブジェクト)をリテラルで与える場合は、__refineV()__を介在させずに、成功します。

sbtConsole
scala> val positive: Int Refined Positive = 10
val positive: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive] = 10
scala>

valで、数値を代入(名前束縛)した不変オブジェクトxを定義する

sbtConsole
scala> val x = 10
val x: Int = 10

scala> x
val res33: Int = 10

scala> 

参考にしたウェブページからは、Int型を扱う場合に、refineV()の出力値であるEither型からInt型オブジェクトを取り出す部分が書かれていません。

試行錯誤した経緯を以下に掲載します。

試行錯誤の経緯

refineV()を作用させずに、xをそのまま使って、Positive型のオブジェクトを初期化宣言すると、エラーが吐かれます。

sbtConsole
scala> val positive: Int Refined Positive = x
                                            ^
       error: compile-time refinement only works with literals

scala>
  • refineV(x)を使って、Positive型のオブジェクトを初期化宣言する
  • なぜかエラーになる
  • エラーメッセージを見ると、polymorphicなオブジェクト(式:expression)はNGとのこと
sbtConsole
scala> val new_positive: Int Refined Positive = refineV(x)
                                                       ^
       error: polymorphic expression cannot be instantiated to expected type;
        found   : [P]Either[String,eu.timepit.refined.api.Refined[Int,P]]
        required: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive]
           (which expands to)  eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Greater[shapeless._0]]

scala> 

( 参考にしたウェブページ )

リテラルでない値についてはコンパイル時に値の性質がわからないため、自動でRefineされた型の値に変換することはできません。 このような場合にはrefineVを使用します。

// Macros can only validate literals because their values are known at
// compile-time. To validate arbitrary (runtime) values we can use the
// refineV function:

scala> val x = 42 // suppose the value of x is not known at compile-time

scala> refineV[Positive](x)
res1: Either[String, Int Refined Positive] = Right(42)

scala> refineV[Positive](-x)
res2: Either[String, Int Refined Positive] = Left(Predicate failed: (-42 > 0).)
  • refineVPositiveを実行すると、Either型が出力されます。
sbtConsole
scala> refineV[Positive](x)
val res3: Either[String,eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive]] = Right(3)

scala> refineV[Positive](-x)
val res4: Either[String,eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive]] = Left(Predicate failed: (-3 > 0).)

scala> 

次を実行してみます。

sbtConsole
scala> val new_positive: Int Refined Positive = refineV[Positive](x)
                                                                 ^
       error: type mismatch;
        found   : Either[String,eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive]]
           (which expands to)  Either[String,eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Greater[shapeless._0]]]
        required: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive]
           (which expands to)  eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Greater[shapeless._0]]

scala> 

エラーメッセージの内容は、次の通りです。

  • refineVPositiveで生成されるオブジェクトは、 Either[String,eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive]]型になる。

  • 求められているのはEither型ではなく、eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive]型だ。

エラーメッセージ

found : Either[String,eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive]]
(which expands to) Either[String,eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Greater[shapeless._0]]]
required: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive]
(which expands to) eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Greater[shapeless._0]]



EitherのRightから、格納された値を取り出す。(数値を代入しているので、Either.LeftのNoneには該当しないはず)

- 出力されるEither型のオブジェクトには、Right部分に、入力値__*x*__を評価した計算結果である__*x*__が格納さています。

```Scala:sbtConsole
scala> refineV[Positive](x).isRight
val res26: Boolean = true

scala> 
  • Right部分の中身を表示してみる。
sbtConsole
scala> refineV[Positive](x).right
warning: 1 deprecation (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val res25: scala.util.Either.RightProjection[String,eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive]] = RightProjection(Right(3))

scala>
  • getで値を取り出す。
sbtConsole
scala> refineV[Positive](x).right.get
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val res24: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive] = 3


scala> 

Either.right.getを名前束縛(代入)すると、成功する

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> 

__refineVPositive.right.getはストローク数が長いので、refineV()に入力する式を、一時変数temp__に名前束縛(代入)して使う書き方が適切かもしれません。

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> 

refineMVというものがあるが、うまく使えない

sbtConsole
scala> refineMV[Positive](5)
val res30: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive] = 5

scala> x
val res29: Int = 3


scala> refineMV(x)
               ^
       error: could not find implicit value for parameter v: eu.timepit.refined.api.Validate[Int,P]

scala> refineMV[Positive](x)
                         ^
       error: compile-time refinement only works with literals

scala> val y = 42
val y: Int = 42

scala> refineMV[Positive](y)
                         ^
       error: compile-time refinement only works with literals

scala> 

この__refineMV__は、次のように使えるらしい。

まず分母の型の非ゼロ整数から。

refined でInt Refined Not[Equal[_0]]と書けるが、ここでは二つの型エイリアスに分けた。
val one: NonZeroInt = refineMV[NonZero] (1)のように書ける。

type NonZero    = Not[Equal[_0]]
type NonZeroInt = Int Refined NonZero

オブジェクトoneが属する__型NonZeroInt型__と、refineMVNonZeroから出力される__型__が等しい型になる、ということのようだ。

なお、Qiitaではmarkdownの機能のせいか、文字化けしている。
__refineMVNonZero__は、__refineMV__に続けて、[ ]と、(1)を記述しています。

つまり、NonZeroInt型__と__等しい型__が、refineMV[Not[Equal[_0]]] (1)__を実行した結果、得られるということらしい。

*refineMV()*関数__の入力値(引数)は__1__であり、その型は、暗黙の型推論で__Int型__と判断されるため、refineMVNot[Equal[_0]]は、Not[Equal[_0]]__として定義される__NonZero型__に、Int型__を付加した__Int Refined NonZero型(のエイリアスである)NonZeroInt型__と__等しくなる、ということと思われる。

String型を扱う場合

参考にしたウェブページでは、文字列はリテラル値しか渡していません。

 //文字列"hoge"から始まる
 val startsWithHoge: String Refined StartsWith[W.`"hoge"`.T] = "hogefuga"

 //パターンにマッチする
 val matched: String Refined MatchesRegex[W.`"[a-z]0[A-Z]+"`.T] = "a0AHFOEHF"

String型のリテラル値(文字列)を格納した変数を扱う場合を試してみます。

sbtConsole
scala> val x  = "hogefuga" 
val x: String = hogefuga

scala> x
val res36: String = hogefuga

scala> refineV(x)
              ^
       error: could not find implicit value for parameter v: eu.timepit.refined.api.Validate[String,P]

scala> refineV[String](x)
                      ^
       error: could not find implicit value for parameter v: eu.timepit.refined.api.Validate[String,String]

scala>

Refineで定義済みの値制約の述語(predicate)をrefineV[]に渡してみる。

  • Either型が返される(Int型と同じ)
sbtConsole
scala> refineV[EndsWith["A"]](x)
val res43: Either[String,eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.EndsWith["A"]]] = Left(Predicate failed: "hogefuga".endsWith("A").)

scala> refineV[StartsWith["A"]](x)
val res44: Either[String,eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.StartsWith["A"]]] = Left(Predicate failed: "hogefuga".startsWith("A").)

scala> 
  • Int型と同様に、Either型から入力したInt型オブジェクトを取り出すために、Either.right.get()関数を実行するコードを1行追加する必要があります。
sbtConsole
scala> refineV[StartsWith["A"]](x).isRight
val res47: Boolean = false

scala>

ここで、__xには、"hogehoge"が名前束縛されています。この値は、"A"__で始まる文字列ではないので、Either型のRight側には値は入っていません。

sbtConsole
scala> x
val res48: String = hogefuga

scala>

__refineV([])に、「hで始まる文字列」という値制約条件を定義するStartsWith["h"]__をセットします。

sbtConsole
scala> refineV[StartsWith["h"]](x).isRight
val res49: Boolean = true

scala> refineV[StartsWith["h"]](x).right.get()
                                            ^
       error: eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.StartsWith["h"]] does not take parameters

scala>

_ Warningが表示されますが、__val res51: eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.StartsWith["h"]] = hogefuga__と意図した通りに表示されます。

sbtConsole
scala> refineV[StartsWith["h"]](x).right.get
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val res51: eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.StartsWith["h"]] = hogefuga

scala>

refineV([])に入力する式__StartsWith["h"]が長いので、efineVStartsWith["h"].right.getを一時変数temp__に名前束縛(代入)します。

sbtConsole
scala> val temp = refineV[StartsWith["h"]](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[String,eu.timepit.refined.string.StartsWith["h"]] = hogefuga

scala>
  • 意図した通りの結果が得られました。
sbtConsole
scala> temp
val res52: eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.StartsWith["h"]] = hogefuga

ところで、以下はエラーになります。

sbtConsole
scala> val startsWithHoge: String Refined StartsWith[W.`"hoge"`.T] = refineV[StartsWith["h"]](x).right.get
                                                                                                       ^
       error: type mismatch (invalid inference):
        eu.timepit.refined.string.StartsWith["h"] does not imply
        eu.timepit.refined.string.StartsWith[String("hoge")]

scala>

左辺の式では、値制約__String Refined StartsWith[W."hoge".T]が付いているのに対して、右辺では、値制約StartsWith["h"]__が付いており、制約条件が一致しないからです。
("hoge"と"h"が一致しない)

右辺の値制約条件を__StartsWith["hoge"]__にすると、実行できるようになります。

sbtConsole
scala> val startsWithHoge: String Refined StartsWith[W.`"hoge"`.T] = refineV[StartsWith["hoge"]](x).right.get
warning: 2 deprecations (since 2.13.0); for details, enable `:setting -deprecation` or `:replay -deprecation`
val startsWithHoge: eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.StartsWith[String("hoge")]] = hogefuga

scala> 
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?