Thursday, November 30, 2017

Type Classes in Scala



Type classes are useful in providing an interface implementation types without the types implementing the interface themselves i.e. the interface implementation is independent of the type source code.

Hence, type classes can be used to extend the functionality of even those classes for which the source code is not available.

Examples:
Numeric[T] and Ordering[T] are examples of type classes in the Scala library.

Numeric[T] provides a unified interface for all numeric types in Scala even though the numeric types do not share a common super type.

Ordering[T] provides an interface for implementing ordering strategy/logic for sorting a type.

Note
Type classes are not first order citizens in Scala. They are instead implemented via a combination of the following:
  1. traits - for defining the interface
  2. implicit objects - for defining the concrete implementation of the defined trait
  3. parameterised curried method with an implicit parameter list - for restricting the type variable T to the types that have implementations of the defined trait
 Example:

Below is an example of a trait 'MyStringLike' that has a method 'len' which returns the length of a type A value.

The companion object implements MyStringLike[A] for type = Int


trait MyStringLike[A] {
 def len(x : A): Int
}

object MyStringLike {
  implicit object MyStringLikeInt extends MyStringLike[Int] {
    def len(x: Int) = x.toString.length
  }
}


The following are 2 different implementations of the length method which makes use of type class 'MyStringLike' to return the length of some type A for which an implementation of MyStringLike[A] exists.



import MyStringLike._

def mylen[T](x: T)(implicit v: MyStringLike[T]) = v.len(x)
mylen: [T](x: T)(implicit v: MyStringLike[T])Int

def mylen2[T : MyStringLike](x: T) = implicitly[MyStringLike[T]].len(x)
mylen2: [T](x: T)(implicit evidence$1: MyStringLike[T])Int


The 2nd variant where the implicit parameter list is absent is referred to as the context bound notation. Here the type variable T is restricted those types for which MyStringLike[T] implementation exists.


References

[1] https://www.cakesolutions.net/teamblogs/demystifying-implicits-and-typeclasses-in-scala
[2] http://blog.muhuk.com/2013/09/29/unified_support_for_numbers_in_scala.html#.Wh988rT1VR1
[3] http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html

Wednesday, November 29, 2017

Type constructors, Higher Kinded Types etc.



Type Constructors

Type constructors can be thought of as functions that take a type as an argument instead of a value.

Example:

List[+A] is a type constructor

Here, A is a type variable

Higher Kinded Types (HKT's)

A set of types of the same kind are referred to as HKTs.
For example, there can be several types of lists. Hence, list can be considered a HKT.

There is also an order associated with the HKT.

In fact, List is considered as a higher kinded type of the 1st order.


scala:k List
List's kind is F[+A]

scala:k -v List
List's kind is F[+A]
* -(+)-> *


This is a type constructor: a 1st-order-kinded type.


Functors

Functor is a map function that, given 

  • a function 'f: A => B' and 
  • a value wrapped in a context 'F[A]'

can unwrap the value inside F[A], apply the function f to the value to generate value of type B and wrap the same inside context F to generate F[B]

scalatrait Functor[F[_]] {
       def map[A,B](fa: F[A])(f: A => B): F[B]
     }
defined trait Functor

scala:k -v Functor
Functor's kind is X[F[A]]
(* -> *) -> *

This is a type constructor that takes type constructor(s): a higher-kinded type.


Functor is a higher kinded type of the 2nd order as it's type constructor takes type constructor as argument.


Monads

Monad is a transformation function that given f: A => F[B] and F[A], applies the function f to the value in F[A] and wraps the result in the context F i.e. F[F[B]] which is then further flattened get F[B].


scalatrait Monad[F[_]] {
       def flatMap[A,B](fa: F[A])(f: A => F[B]): F[B]
     }
defined trait Monad

scala:k -v Monad
Monad's kind is X[F[A]]
(* -> *) -> *

This is a type constructor that takes type constructor(s): a higher-kinded type.


Applicatives

Applicative is a transformation construct that given a function wrapped inside a context F[A => B] and value wrapped inside a context F[A], unwraps both the function & value, applies the function to the value to generate a type B value and wraps it inside the context F to generate F[B]


scalatrait Applicative[F[_]] {
       def apply[A,B](fa: F[A])(fab: F[A => B]): F[B]
     }
defined trait Applicative

scala:k -v Applicative
Applicative's kind is X[F[A]]
(* -> *) -> *


This is a type constructor that takes type constructor(s): a higher-kinded type.

References

[1] https://thedet.wordpress.com/2012/04/28/functors-monads-applicatives-can-be-so-simple/
[2] https://thedet.wordpress.com/2012/05/04/functors-monads-applicatives-different-implementations/

Friday, November 24, 2017

For comprehensions - Syntactic sugar for flatMap & map


Given the following definitions...


def getX = Option(List(3))

def getY = Option(List(5))


The below 2 computations are the same:


getX.flatMap(x => getY.map(y => x ++ y))



val z = for {
       x <- getX
       y <- getY

     } yield x ++ y


Value of z:



z: Option[List[Int]] = Some(List(3, 5))