Last active
August 25, 2017 19:10
-
-
Save jiamingd/29c7c8ca639b3c8f366088e0b651040a to your computer and use it in GitHub Desktop.
f-bound vs type inference drill
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait Pet { | |
def name : String | |
} | |
trait Renamable[A] { | |
def rename( a: A, newName: String): A | |
} | |
case class Fish(name: String, age: Int) | |
object Fish { | |
// Type class | |
implicit val fishRename = new Renamable[Fish] { | |
override def rename(f: Fish, newName: String): Fish = { | |
f.copy(name = newName) | |
} | |
} | |
} | |
//implicit class must have primary constructor with just 1 args in first curreied param lsit | |
implicit class HelpTool[A](a:A)(implicit renamable: Renamable[A]) { | |
def doRename[A](newName: String)= { | |
renamable.rename(a, newName) | |
} | |
} | |
val oldFish = Fish("Jon", 2) | |
val oldFishNewName = oldFish.doRename("Mike") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//This is just to show why we need F-Bound type | |
trait Pet { | |
def name: String | |
def renamed(newName: String): Pet | |
// This Approach fail on compile | |
// def esquire[A <: Pet](a: A): A = a.renamed(a.name + ", Esq.") | |
} | |
case class Fish(name: String, age: Int) extends Pet { | |
// This is allowed because return types are in covariant position; | |
// it’s always ok to return something more specific than what is promised. | |
def renamed(newName: String): Fish = copy(name = newName) | |
} | |
case class Kitty(name: String, color: String) extends Pet { | |
def renamed(newName: String): Fish = new Fish(newName, 42) // oops, Not Cat? We need more constrain | |
} | |
// An F-bounded type is parameterized over its own subtypes, which allows us to “pass” the | |
// implementing type as an argument to the superclass. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// demo F-bound polymorhism | |
trait Juicable[E <: Juicable[E]] { self: E => //restrict the implementing class claiming to be an A to actually be an A | |
def makeJuice(id: String): E | |
} | |
case class Apple(name: String, age: Int) extends Juicable[Apple] { | |
//restrict the implementing class claiming to be an A to actually be an A | |
override def makeJuice(id: String): Apple = Apple("a", 8) | |
} | |
// Below will fail compile as E conflict on Apple vs Orange, because of "self: E =>" | |
//case class Orange(name: String, age: Int) extends Juicable[Apple] | |
// But looks like this still working for return type change !!! ????? | |
case class Orange(name: String, age: Int) extends Juicable[Orange] { | |
//restrict the implementing class claiming to be an A to actually be an A | |
override def makeJuice(id: String): Apple = Apple("a", 8) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait Juicable[E] { | |
def makeJuice(): Unit | |
} | |
case class Apple(name: String, weight: Int) | |
object Apple { | |
// companion object | |
implicit val ja = new Juicable[Apple] { | |
override def makeJuice(): Unit = { | |
println(s"making juice from apple") | |
} | |
} | |
} | |
def execJuice[F]( f : F)(implicit juicable: Juicable[F]) = { | |
juicable.makeJuice() | |
} | |
val a = Apple("fuji", 10) | |
execJuice(a) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://gist.github.com/jiamingd/29c7c8ca639b3c8f366088e0b651040a#file-playfbound-L2 seems if the self: E=> declaration removed the compiler will still tell you type incompatible.