Pages

Sunday 18 October 2015

Typeclass in Scala and Haskell

In this post I would like to present an example of Typeclass in Scala and compare it with the equivalent Haskell syntax.

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

5 comments:

  1. The article is really nice and concise. It would be better to clarify that you are using a technique named the "pimp my library pattern" in which any List having an instance of Priceable implicitly available will benefit from the totalPrice method, not any List.

    ReplyDelete
    Replies
    1. Hi Tom good point, I was focusing the article more on the syntax similarity between the 2 languages but I think you are right and is beneficial for the reader to know more about patterns available in scala, for this reason I will paste here the link to Martin Odersky post on "pimp my library pattern", thanks for the comment ;-) : http://www.artima.com/weblogs/viewpost.jsp?thread=179766

      Delete
  2. Thanks to my friend Andy who immediately spotted my mistake on 'JJ Tolkien' name :-(, sorry for all the LOTR funs, this has now been fixed :-)

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Great article, Patrick! I am going to share this!

    ReplyDelete