The purpose of this article is to prove that Scala inherits lots of the elements and syntax from FP languages such as Haskell and is not just a Java++ with a nicer lambda expressions.
In this exercise we would like to implement a simple method:
Scala
def totalPrice[P:Priceable](ps:List[P]):Double // Scala
Haskell
totalPrice :: Priceable p => [p] -> Double -- Haskell
In order to compile the method we need to give a definition for Priceable. We want Priceable to be a Typeclass, all the priceable entities must provide a method to extract the price as Double.
Scala:
trait Priceable[-A] { def extractPrice(a:A):Double }
Haskell:
class Priceable a where extractPrice :: a -> Double
Now that we have defined the Typeclass we can go back to our original method and provide the implementation:
Scala
package object exercise { def totalPrice[P:Priceable](ps:List[P]):Double = ps.map(implicitly[Priceable[P]].extractPrice).reduce(_+_) }
Haskell
totalPrice ps = foldr1 (+) (map extractPrice ps)
Finally we can create our entity Book:
Scala
case class Book(title:String, author:String, price:Double)
Haskell
data Book = Book { title::String, author::String, price::Double }
and make it member of Priceable:
Scala
object Book { implicit val bookPriceable = new Priceable[Book] { def extractPrice(book:Book):Double = book.price } }
Haskell
instance Priceable Book where extractPrice book = price book
Now lets create few books and use the priceTotal function:
Scala
val book1 = Book("The Fellowship of the Ring", "J. R. R. Tolkien", 31.45) val book2 = Book("The Da Vinci Code", "Dan Brown", 22.55) val book3 = Book("Timeline", "Michael Crichton", 21.50) val books = List(book1, book2, book3) totalPrice(books) // res0 = 75.50
Haskell
book1 = Book "The Fellowship of the Ring" "J. R. R. Tolkien" 31.45 book2 = Book "The Da Vinci Code" "Dan Brown" 22.55 book3 = Book "Timeline" "Michael Crichton" 21.50 books = [book1, book2, book3] totalPrice books -- res0 = 75.50
In Scala we can also wrap the List[P:Priceable] into an implicit class to have a more (.) oriented notation:
implicit class PriceableOp[P:Priceable](ps:List[P]) { lazy val totalPrice = exercise.totalPrice(ps) }
So now in is possible to write:
val book1 = Book("The Fellowship of the Ring", "J. R. R. Tolkien", 31.45) val book2 = Book("The Da Vinci Code", "Dan Brown", 22.55) val book3 = Book("Timeline", "Michael Crichton", 21.50) val books = List(book1, book2, book3) val result = books.totalPrice
If you want to learn more about the usage of implicit in Scala, here is a post of method extension strategy via implicit:
http://patricknoir.blogspot.com.es/2014/12/method-extension-in-scala-with-implicit.html