How to choose typeclass by dynamic input in Scala

116

Solution 1

I think, your problem is that Map is a wrong way to represent this. Use a case class:

    case class Foo(
       name: Rep[Option[String]], 
       email: Rep[String], 
       score: Rep[Int]
    )

    def applyRater[T : Rater](t: T) = implicitly[Rater[T]](t)
    def rate(foo: Foo, what: String) = what match {
      case "name" => applyRater(foo.name)
      case "email" => applyRater(foo.email)
      case "score" => applyRater(foo.score)
      case _ => default
    }
    

Solution 2

[AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Index(FormCollection collection)
    {
         string valueFromNameTextBox = collection["name"];
    }

You can index into this collection with the names of all the inputs on the form.

Share:
116
Kotofey
Author by

Kotofey

Updated on December 19, 2022

Comments

  • Kotofey
    Kotofey over 1 year

    Have a slick table with columns:

    def name: Rep[Option[String]] = ???
    def email: Rep[String] = ???
    def fraudScores: Rep[Int] = ???
    

    also there is typeclass to calcualte rate for different fields:

    trait Rater[T] {
      def apply(rep: T): Result
    }
    
    object Rater {
      def getRater[T](t: T)(implicit rater: Rater[T]): Result = rater(t)
    
      implicit val int: Rater[Rep[Int]] = v => calculateRate(v, _)
      implicit val str: Rater[Rep[String]] = v => calculateRate(v, _)
      implicit val strOpt: Rater[Rep[Option[String]]] = v => calculateRate(v, _)
    }
    

    and map:

    val map: Map[String, Rep[_ >: Option[String] with String with Int]] = Map(
      "name" -> name,
      "email" -> email,
      "scores" -> fraudScores
    )
    

    what I'd like to do is getting correct instance based on dynamic input, like:

    val fname = "scores" // value getting from http request
    map.get(fname).fold(default)(f => {
        val rater = getRater(f)
        rater(someVal)
    })
    

    but getting error that there is no implicit for Rep[_ >: Option[String] with String with Int], is there some workaround for this?

  • Kotofey
    Kotofey about 3 years
    Hey, thanks for answer! I can see one disadvantage of this approach - every time someone change the type of field in table it have to not forget to change type of field also in case class. Would love to see if it can be done without this.
  • Dima
    Dima about 3 years
    @kotofey, well I am not familiar with slick, but perhaps there is a way to just use the ORM class directly instead of additional case class? Also you don't really jave to remember to change the type in the case class: it simply will not compile if you forget.
  • Kotofey
    Kotofey about 3 years
    you're right it - will not compile, so it is a possible solution. But in case if there is a lot of fields in Foo and also need to have more than one functions like rate it looks not so good and would be really good to reduce boilerplate.