简体   繁体   中英

Trying to keep types unwrapped when using refined

I am trying to use refined to create smart constructors based on primitives and avoid wrapping since same types might be used in large collections. Am I doing this right? Seems to work but a bit boilerplaty

    type ONE_Pred = = MatchesRegex[W....
    type ONE = String @@ ONE_Pred
    type TWO_Pred = OneOf[...
    type TWO = String @@ TWO_PRED 

and then

 case class C(one:ONE, two:TWO)
 object C {
  def apply(one:String, two:String):Either[String, C] = 
  (
   refineT[ONE_Pred](one),
   refineT[TWO_Pred](two)
  ).mapN(C.apply)
}

Refined has a mechanism for creating a companion-like objects that have some utilites already defined:

type ONE = String @@ MatchesRegex["\\d+"]
object ONE extends RefinedTypeOps[ONE, String]

Note that:

  1. You don't need a predicate type to be mentioned separately
  2. It works for both shapeless tags and refined own newtypes. The flavor you get is based on the structure of type ONE .

You get:

  • ONE("literal") as alternative to refineMT / refineMV
  • ONE.from(string) as alternative to refineT / refineV
  • ONE.unapply so you can do string match { case ONE(taggedValue) =>... }
  • ONE.unsafeFrom for when your only option is to throw an exception.

With these "companions", it's possible to write much simpler code with no need to mention any predicate types:

object C {
  def apply(one: String, two: String): Either[String, C] =
    (ONE.from(one), TWO.from(two)).mapN(C.apply)
}

(example in scastie , using 2.13 with native literal types)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM