implicit conversions that add properties to a type, rather than to an instance of a type

时间秒杀一切 提交于 2019-12-10 11:06:30

问题


I was reading through some older Scala posts to better understand type classes, and I ran across this one that seemed quite useful, but the example seems to have gotten stale.

Can someone help me figure out the correct way to do what Phillipe intended ? Here is the code

trait Default[T] { def value : T }

implicit object DefaultInt extends Default[Int] {
  def value = 42
}

implicit def listsHaveDefault[T : Default] = new Default[List[T]] {
  def value = implicitly[Default[T]].value :: Nil
}

default[List[List[Int]]]

When copy/pasted and run in REPL, i get this>

    scala> default[List[List[Int]]]
    <console>:18: error: not found: value default
                  default[List[List[Int]]]
                  ^

回答1:


This doesn't have anything to do with the Scala version. If you read @Philippe's answer, you will notice that the default method simply isn't defined anywhere. That will not work in any Scala version.

It should look something like this:

def default[T: Default] = implicitly[Default[T]].value



回答2:


Thanks to Jorg for his answer, which, in conjunction with this blog post helped me figure out what is going on here. Hopefully my additional answer will help others who have been confused by this.

My mental picture of type classes is that they are a means by which an author of a library would imbue his/her library with the desireable trait of retroactive extensibility.

On the other hand, there is yet another technique for ad hoc polymorphism: implicits with wrapper classes. You would use this latter technique when you are the consumer of a library which has some type which is missing methods that you find useful.

I am going to try to extend Phillipe's example a bit to illustrate my understanding of how type classes could be used by a library designer. I am not that experienced with Scala... so if anyone notices something that is not correct in my understanding please do correct me ! ;^)

// 'Default' defines a trait that represents the ability to  manufacture
// defaults for a particular type 'T'.
//
trait Default[T] { def value : T }


// Define a default for int.. this is an object default
//
implicit object DefaultInt extends Default[Int] {
      def value = 42
}


// Define a default for Lists that contain instances of a 'T'.
// Interesting that this is method, not an object implicit definition. I
// guess that is to enable the 'on the fly' creation of default values for
// lists of any old type....  So I guess that's why we have 
// a 'method implicit' rather than an 'object implicit' definition.

implicit def listsHaveDefault[T : Default] = new Default[List[T]] {
  def value = implicitly[Default[T]].value :: Nil
}



// Here is the meat of the library... a method to make a message based of
// some arbitrary seed String, where that method is parameterized by 'T',
// a type chosen by the library user.   That 'T' can be 
// types for which implicits are already defined by the base library 
// (T = Int, and List[T]), or an implicit defined by the library user.   
//
// So the library is open for extension.
//
def makeMsg[T](msg: String)(implicit something: Default[T]) : String = {
    msg + something.value
} 

Given the above code, if I can create a message for the type List[List[Int]], or for Int's

makeMsg[List[List[Int]]]("moocow-")
makeMsg[Int]("dogbox")

And I get this result:

res0: String = moocow-List(List(42))
res1: String = dogbox42

If I want to override the default implicit value for a given type, I can do so like this:

makeMsg[Int]("moocow-")(something=new Object with Default[Int] { def value = 33344 }  )

And I get this result:

res3: String = moocow-33344


来源:https://stackoverflow.com/questions/31910923/implicit-conversions-that-add-properties-to-a-type-rather-than-to-an-instance-o

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!