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__が渡された場合も、等しく正常に動作します。
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"__が渡された場合も、等しく正常に動作します。
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
この関数は、以下のように定義すると、引数として、リテラル値の整数が渡された場合も、変数に格納(名前束縛)された整数が渡された場合も、値検査を行った上で、正常に動作します。
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>
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側で対応させたいところではあります。
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__というエイリアスを付けます。
scala> type NonEmptyCollection = Seq[String] Refined NonEmpty
type NonEmptyCollection
scala>
次に、valキーワードで不変型のオブジェクト__string__を定義します。
このオブジェクトは、"hoge", "fuga", "tom"という3つのString型オブジェクトを要素として持ちます。
scala> val strings = List("hoge", "fuga", "tom")
val strings: List[String] = List(hoge, fuga, tom)
定義した変数__stringsで、*Either[String, NonEmptyCollection]*型__のオブジェクトをvalキーワードで定義すると、エラーが返されます。
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)を値束縛すると、エラーを吐くことなく成功しました。
scala> val nonEmpty: Either[String, NonEmptyCollection] = refineV(strings)
val nonEmpty: Either[String,NonEmptyCollection] = Right(List(hoge, fuga, tom))
scala>
-nonEmptyには意図した通りに、値が格納(名前束縛)されました。
scala> nonEmpty
val res19: Either[String,NonEmptyCollection] = Right(List(hoge, fuga, tom))
参考ウェブページにある次のコードも、エラーが出ずに実行できます。
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__をそのまま与えると、エラーになります。
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宣言)
この方法で、成功します。
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>
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()__を介在させずに、成功します。
scala> val positive: Int Refined Positive = 10
val positive: eu.timepit.refined.api.Refined[Int,eu.timepit.refined.numeric.Positive] = 10
scala>
valで、数値を代入(名前束縛)した不変オブジェクトxを定義する
scala> val x = 10
val x: Int = 10
scala> x
val res33: Int = 10
scala>
参考にしたウェブページからは、Int型を扱う場合に、refineV()の出力値であるEither型からInt型オブジェクトを取り出す部分が書かれていません。
試行錯誤した経緯を以下に掲載します。
試行錯誤の経緯
refineV()を作用させずに、xをそのまま使って、Positive型のオブジェクトを初期化宣言すると、エラーが吐かれます。
scala> val positive: Int Refined Positive = x
^
error: compile-time refinement only works with literals
scala>
- refineV(x)を使って、Positive型のオブジェクトを初期化宣言する
- なぜかエラーになる
- エラーメッセージを見ると、polymorphicなオブジェクト(式:expression)はNGとのこと
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型が出力されます。
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>
次を実行してみます。
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部分の中身を表示してみる。
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で値を取り出す。
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を名前束縛(代入)すると、成功する
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__に名前束縛(代入)して使う書き方が適切かもしれません。
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というものがあるが、うまく使えない
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型のリテラル値(文字列)を格納した変数を扱う場合を試してみます。
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型と同じ)
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行追加する必要があります。
scala> refineV[StartsWith["A"]](x).isRight
val res47: Boolean = false
scala>
ここで、__xには、"hogehoge"が名前束縛されています。この値は、"A"__で始まる文字列ではないので、Either型のRight側には値は入っていません。
scala> x
val res48: String = hogefuga
scala>
__refineV([])に、「hで始まる文字列」という値制約条件を定義するStartsWith["h"]__をセットします。
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__と意図した通りに表示されます。
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__に名前束縛(代入)します。
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>
- 意図した通りの結果が得られました。
scala> temp
val res52: eu.timepit.refined.api.Refined[String,eu.timepit.refined.string.StartsWith["h"]] = hogefuga
ところで、以下はエラーになります。
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"]__にすると、実行できるようになります。
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>