Scala is a general purpose programming language designed to express common programming patterns in a concise, elegant, and type-safe way. It smoothly integrates features of object-oriented and functional languages, enabling Java and other programmers to be more productive. Code sizes are typically reduced by a factor of two to three when compared to an equivalent Java application.

FP important data structure in Scala

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
  trait Monoid[A] {
    def zero: A
    def op(x: A, y: A): A
  }

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

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

  trait Monad[F[_]] {
    def unit[A](a: A): F[A]
    def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
    // map can be implemented using flatMap and unit
    def map[A, B](fa: F[A])(f: A => B): F[B] = flatMap(fa)(a => unit[B](f(a)))
  }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  case class Foo[A](foo: A)

  val fooFunctor: Functor[Foo] = new Functor[Foo] {
    override def map[A, B](fa: Foo[A])(f: A => B): Foo[B] = Foo[B](f(fa.foo))
  }

  val fooApplicative: Applicative[Foo] = new Applicative[Foo] {
    override def apply[A, B](fa: Foo[A])(f: Foo[A => B]): Foo[B] = Foo(f.foo(fa.foo))
  }

  val fooMonad: Monad[Foo] = new Monad[Foo] {
    override def unit[A](a: A): Foo[A] = Foo[A](a)
    override def flatMap[A, B](fa: Foo[A])(f: A => Foo[B]): Foo[B] = f(fa.foo)
  }

Magnet pattern

A well presentation of the Magnet Pattern is posted here. Let write a simple example based on that presentation:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  sealed trait Magnet {
    type Result
    def apply(): Result
  }

  object Magnet {
    
    implicit def fromInt(tuple: (Int, String)) = new Magnet {
      type Result = String
      def apply(): Result = tuple._1.toString() + tuple._2
    }
    
    implicit def fromUnit(u: Unit) = new Magnet {
      type Result = Int
      def apply() = "foo".hashCode()
    }
    
    implicit def fromString(u: String) = new Magnet {
      type Result = String
      def apply() = u
    }
    
  }
  
  def complete(magnet: Magnet): magnet.Result = magnet()

  println(complete(25, " years")) // will call fromInt
  println(complete("magnet pattern")) // will call fromUnit
  println(complete()) // will call fromString
  println(complete(5)) // compile error
The same example can be designed as a type class:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  sealed trait Magnet[T] {
    def apply(): T
  }

  object Magnet {
    
    implicit def fromInt(tuple: (Int, String)) = new Magnet[String] {
      def apply() = tuple._1.toString() + tuple._2
    }

    implicit def fromUnit(u: Unit) = new Magnet[Int] {
      def apply() = "foo".hashCode()
    }

    implicit def fromString(u: String) = new Magnet[String] {
      def apply() = u
    }
  
  }

  def complete[T](magnet: Magnet[T]): T = magnet()

  println(complete(25, " years")) // will call fromInt
  println(complete("magnet pattern")) // will call fromUnit
  println(complete()) // will call fromString
  println(complete(5)) // compile error
But Magnet trait looks pretty much the same as Function0 trait! Let try to replace our Magnet trait with a Function0 trait.
1
def complete[T](f: Function0[T]): T = f()
or using lambdas:
1
def complete[T](f: () => T): T = f()
and rewrite implicits as follow:
1
2
3
implicit def fromInt(tuple: (Int, String)) = new Function0[String] {
    def apply() = tuple._1.toString() + tuple._2
}
or using lambdas:
1
2
implicit def fromInt(tuple: (Int, String)) = 
    () => tuple._1.toString() + tuple._2
The results are the same as using Magnet trait.

Type safe equals

Yet another simple example which is a potential solution on how to implement type safe equals.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
object TypeSafeEquals {

  trait Equal[A] {
    def ===(a: A): Boolean
    def =/=(a: A): Boolean
  }

  implicit class Equals[A](a: A) extends Equal[A] {
    override def ===(b: A) = a == b
    override def =/=(b: A) = a != b
  }
}

object Main extends App {

  import TypeSafeEquals._

  println("123" == 123)       // print false
  println(123 == "123")       // print false
  println("123" === 123)      // compile error (type mismatch)
  println(123 === "123")      // compile error (type mismatch)

  println("123" === "123")    // print true
  println("123" =/= "123")    // print false
  println("123" === "124")    // print false
  println("123" =/= "124")    // print true
}

Partial functions

A partial function of type PartialFunction[A, B] is a unary function where the domain does not necessarily include all values of type A. The function isDefinedAt allows to test dynamically if a value is in the domain of the function. The trait PartialFunction define two abstract methods:
  abstract def apply(v1: A): B
  Apply the body of this function to the argument.

  abstract def isDefinedAt(x: A): Boolean
  Checks if a value is contained in the function's domain.
Whenever we create an instance of a PartialFunction we must provide implementation for both abstract methods. Example:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
  val pfc = new PartialFunction[Int, String] {

    override def apply(x: Int) = x match {
      case 0 => "zero"
      case 1 => "one"
    }

    override def isDefinedAt(x: Int) = x match {
      case 0 | 1 => true
      case _ => false
    }
  }

  println(if (pfc.isDefinedAt(0)) pfc(0) else "Undefined for 0")
  println(if (pfc.isDefinedAt(1)) pfc(1) else "Undefined for 1")
  println(pfc.isDefinedAt(9))
The printed results as we expect are "zero", "one", false.
From The Scala Language Specification: “An anonymous function can be defined by a sequence of cases […] which appear as an expression without a prior match.” Let write the same example as an anonymous function.
1
2
3
4
5
6
7
8
9
  val pf: PartialFunction[Int, String] = {
    case 0 => "zero"
    case 1 => "one"
    // case _ => "total"
  }

  println(if (pf.isDefinedAt(0)) pf(0) /* pf.apply(0) */ else "Undefined for 0")
  println(if (pf.isDefinedAt(1)) pf(1) else "Undefined for 1")
  println(pf.isDefinedAt(9))
The printed results are the same as in previous example, "zero", "one", false but the code is from far much more elegant. Finally let transform our partial function into a total function by adding a new case statement which match any value (see line 4):
1
2
3
4
5
6
7
8
9
  val pf: PartialFunction[Int, String] = {
    case 0 => "zero"
    case 1 => "one"
    case _ => "total"
  }

  println(if (pf.isDefinedAt(0)) pf(0) /* pf.apply(0) */ else "Undefined for 0")
  println(if (pf.isDefinedAt(1)) pf(1) else "Undefined for 1")
  println(pf.isDefinedAt(9))
This time the printed results are "zero", "one", true. In conclusion the case block is compiled as a partial function and compiler provide implementations for both abstract methods, apply and isDefinedAt by the book.
But the case statements block can also generate a Function[A, B]
1
2
3
4
5
6
7
// type Function[-A, +B] = Function1[A, B]
  val f: Function[Int, String] = {
    case 0 => "zero"
    case 1 => "one"
  }

  println(f(0))
In this case only the apply method is implemented because Function1 trait define only apply method as abstract.
  abstract def apply(v1: A): B
  Apply the body of this function to the argument.
From Scala doc: "Note that Function1 does not define a total function, as might be suggested by the existence of PartialFunction. The only distinction between Function1 and PartialFunction is that the latter can specify inputs which it will not handle."

Currying and partial function application

Currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument. (partial application) Methods may define multiple parameter lists. When a method is called with a fewer number of parameter lists, then this will yield a function taking the missing parameter lists as its arguments.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
object Main {
  /* a function having 3 parameters */
  def g(x: Int, y: Int, z: Int) = x + y + z

  /* another function having 3 parameters */
  def p(x: Int)(y: Int)(z: Int) = x + y + z

  /* currying function g or p */
  def f(x: Int) = (y: Int) => (z: Int) => x + y + z

  def main(args: Array[String]): Unit = {
    // will print 14
    println(g(2, 3, 9))
    // currying will print 14
    println(f(2)(3)(9))
    // partial function application will print <function1>
    println(f(2)(3))
    // partial function application will print <function1>
    println(p(2)_)
  }
}

Scala implicit parameters

A method with implicit parameters can be applied to arguments just like a normal method. In this case the implicit label has no effect. However, if such a method misses arguments for its implicit parameters, such arguments will be automatically provided.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
object Main extends App {

  trait Monoid[A] {
    def add(x: A, y: A): A
    def unit: A
  }

  implicit object StringMonoid extends Monoid[String] {
    def add(x: String, y: String): String = x concat y
    def unit: String = ""
  }

  implicit object IntMonoid extends Monoid[Int] {
    def add(x: Int, y: Int): Int = x + y
    def unit: Int = 0
  }

  def sum[A](xs: List[A])(implicit m: Monoid[A]): A =
    xs.foldLeft(m.unit)((s, t) => m.add(s, t))

  println(sum(List(1, 2, 3)))
  println(sum(List("a", "b", "c")))
}

Play framework Google OAuth2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
object OAuth2Google {

  /** Request timeout */
  val REQUEST_TIMEOUT = 10000

  /**
    * Google OAuth2
    *
    * @param accessToken Google access token.
    * @param idToken     Google id token.
    *
    * @return User details
    */
  def apply(accessToken: String, idToken: String):
      Future[Either[Map[String, Option[String]], Throwable] with Product with Serializable] = (
    for {
      valid <- validate(idToken)
      userinfo <- userInfo(accessToken) if valid.status == Status.OK
      date <- dob(accessToken, (userinfo.json \ "sub").as[String]) if userinfo.status == Status.OK
    } yield {
      val birthday = if (date.status == Status.OK) (date.json \ "birthday").asOpt[String] else None
      val json: JsValue = userinfo.json
      Left(Map("user" -> (json \ "sub").asOpt[String],
        "name" -> (json \ "name").asOpt[String],
        "email" -> (json \ "email").asOpt[String],
        "gender" -> (json \ "gender").asOpt[String],
        "picture" -> (json \ "picture").asOpt[String],
        "dob" -> birthday))
    }) recover {
      case t: Throwable => Right(t)
    }

  /**
    * Validate token.
    *
    * @param idToken     Google id token.
    */
  private def validate(idToken: String) = {
    WS.url("https://www.googleapis.com/oauth2/v3/tokeninfo")
      .withRequestTimeout(REQUEST_TIMEOUT)
      .withQueryString("id_token" -> idToken)
      .get
  }

  /**
    * Get user details. (information)
    *
    * @param accessToken Access token.
    */
  private def userInfo(accessToken: String) =
    WS.url("https://www.googleapis.com/oauth2/v3/userinfo")
      .withRequestTimeout(REQUEST_TIMEOUT)
      .withQueryString("alt" -> "json")
      .withQueryString("access_token" -> accessToken)
      .get

  /**
    * Google birthday is accessible only if the user made public the information.
    * The birthday format in JSON response is YYYY-MM-DD
    * Also a Google user could hide the year of birth. The year in response is substituted with 0000 and a
    * typical response in this case looks like 0000-MM-DD
    *
    * @param accessToken Access token
    */
  private def dob(accessToken: String, personId: String) =
    WS.url(s"https://www.googleapis.com/plus/v1/people/$personId")
      .withRequestTimeout(REQUEST_TIMEOUT)
      .withHeaders(HeaderNames.AUTHORIZATION -> s"Bearer $accessToken")
      .get
}

Play framework Facebook OAuth2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
object OAuth2Facebook {

  /** Request timeout */
  val REQUEST_TIMEOUT = 10000

  /**
    * Facebook OAuth2
    *
    * @param accessToken Access token
    * @param userId User ID
    *
    * @return User details
    */
  def apply(accessToken: String, userId: String):
      Future[Either[Map[String, Option[String]], Throwable] with Product with Serializable] = (
    for {
      valid <- validate(accessToken)
      picture <- profilePicture(userId) if valid.status == Status.OK
    } yield {
      val json = valid.json
      val pict = if (picture.status == Status.OK) Option(picture.underlying[Response].getUri.toString) else None
      Left(Map("user" -> (json \ "id").asOpt[String],
        "name" -> (json \ "name").asOpt[String],
        "email" -> (json \ "email").asOpt[String],
        "gender" -> (json \ "gender").asOpt[String],
        "picture" -> pict,
        "dob" -> (json \ "birthday").asOpt[String]))
    }) recover {
      case t: Throwable => Right(t)
    }

  /**
    * Validate Facebook access token
    *
    * @param accessToken Access token
    */
  private def validate(accessToken: String) =
    WS.url("https://graph.facebook.com/v2.4/me")
      .withRequestTimeout(REQUEST_TIMEOUT)
      .withQueryString("access_token" -> accessToken)
      .withQueryString("fields" -> "id,name,email,picture,gender,birthday")
      .get

  /**
    * Get user profile large picture.
    *
    * @param userId Facebook user ID
    */
  private def profilePicture(userId: String) = {
    WS.url(s"https://graph.facebook.com/v2.4/$userId/picture")
      .withRequestTimeout(REQUEST_TIMEOUT)
      .withQueryString("type" -> "large")
      .get
  }
}

Scala AWS S3 API

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
 * This class is a helper used to operate on Amazon Web Services S3 storage.
 * AWS access key and secret key are stored inside configuration file.
 *
 * @author Marius Gligor
 */
object S3 {

  /** Access Key ID */
  val accessKeyId = Config.get("access.key.id")

  /** Secret Access Key */
  val secretAccessKey = Config.get("secret.access.key")

  /**
   * Connect to Amazon S3. Create a client connection based on credentials.
   *
   * @return Amazon S3 connection.
   */
  def connect = Try(new AmazonS3Client(new BasicAWSCredentials(accessKeyId, secretAccessKey)))

  /**
   * Upload a file to S3.
   * <p>
   * 1. Connect to S3
   * 2. Create S3 bucket if bucket does not exist.
   * 3. Upload file to S3.
   *
   * @param bucketName Bucket name.
   * @param key        S3 key (file path in bucket).
   * @param source     File to upload.
   * @param isPublic   <code>true</code> if public access <code>false</code> for private access.
   * @return response
   */
  def upload(bucketName: String, key: String, source: File, isPublic: Boolean) = {
    connect map (s3client => {
      if (!s3client.doesBucketExist(bucketName))
        s3client.createBucket(bucketName)

      s3client.putObject(new PutObjectRequest(bucketName, key, source).withCannedAcl(
        if (isPublic) CannedAccessControlList.PublicRead else CannedAccessControlList.Private))
    })
  }

  /**
   * Download S3 Object.
   *
   * @param bucketName S3 bucket name.
   * @param key        S3 key (file path in bucket).
   * @return S3 Object.
   */
  def download(bucketName: String, key: String) = {
    connect map { s3client =>
      s3client.getObject(new GetObjectRequest(bucketName, key))
    }
  }

  /**
   * Get S3 resource URL.
   *
   * @param bucketName S3 bucket.
   * @param key        Bucket key
   * @return S3 resource URL
   */
  def getResourceUrl(bucketName: String, key: String) = {
    connect map { s3client =>
      s3client.getResourceUrl(bucketName, key)
    }
  }

  /**
   * Check if S3 resource exist.
   *
   * @param bucketName S3 bucket.
   * @param key        Bucket key
   * @return Some[ETag] if resource exists None otherwise.
   */
  def doesResourceExist(bucketName: String, key: String) = {
    connect map { s3client =>
      val objectsList = s3client.listObjects(bucketName, key).getObjectSummaries
      if (objectsList.isEmpty) None else Some(objectsList.get(0).getETag)
    }
  }
}

Scala Play Akka integration

A Play application defines a special actor system to be used by the application. This actor system follows the application life-cycle and restarts automatically when the application restarts. The following code snipped show an example of using Akka in your Play application by creating a router actor running in background.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
 * Manage router actor.
 */
object RouterManager {
  /* number of routee */
  val poolSize = 10

  /* Create router actor */
  val router = Akka.system.actorOf(Props[RouterActor].withRouter(RoundRobinPool(poolSize)))

  /* Initialize */
  def startup() = Logger.info("Startup router manager...")

  /* Stop router actor */
  def shutdown() = {
    router ! Broadcast(PoisonPill)
    Logger.info("Shutdown router manager...")
  }

  /**
   * Send messages to router actor
   * @param message Message to send.
   */
  def send(message: String) = router ! RouterActor.Message(message)
}

/**
 * Router actor companion object.
 */
object RouterActor {
  /* Define your messages here */
  case class Message(message: String)
}

/**
 * Router actor.
 */
class RouterActor extends Actor {
  /* Messages listener */
  def receive = {
    case RouterActor.Message(m) => println("Do something with message " + m)
    case _ => Logger.info("Unknown message!")
  }
}

/**
* Global.scala is used to startup and shutdown router actor 
* when application is started or stopped.
*/
object Global extends GlobalSettings {
  override def onStart(app: Application) {
    Logger.info("Application has been started.")
    RouterManager.startup()
  }

  override def onStop(app: Application) {
    RouterManager.shutdown()
    Logger.info("Application shutdown.")
  }
}

Scala financial

Options pricing Black Scholes model.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
trait Common {

  /**
   * Cumulative Normal Distribution.
   * <p>
   * This is a numerical approximation to the normal distribution.
   * See Abramowitz and Stegun: Handbook of mathematical functions for description.
   * The arguments to the functions are assumed normalized to a (0, 1) distribution.
   *
   * @param z
   */
  def N(z: Double): Double = {
    if (z > 6.0f) {
      1.0
    } else if (z < -6.0f) {
      0.0f
    } else {
      val b1 = 0.31938153f
      val b2 = -0.356563782f
      val b3 = 1.781477937f
      val b4 = -1.821255978f
      val b5 = 1.330274429f
      val p = 0.2316419f
      val c2 = 0.3989423f // 1.0 / Math.sqrt(2.0 * Math.PI)
      val t = 1.0f / (1.0f + Math.abs(z) * p)
      val b = c2 * Math.exp(-z * z / 2.0f)
      val n = ((((b5 * t + b4) * t + b3) * t + b2) * t + b1) * t
      val r = 1.0f - b * n

      if (z < 0.0f) 1.0f - r else r
    }
  }
}

object BlackScholes extends Common {

  /**
   * Black Scholes formula - Option Call common code.
   *
   * @param S     Spot price of underlying asset.
   * @param K     Strike (exercise) price.
   * @param r     Risk free rate (annual rate).
   * @param sigma Volatility
   * @param time  Time to maturity (remaining time, backwards time)
   */
  def optionPrice(S: Double, K: Double, r: Double, sigma: Double, time: Double): (Double, Double) = {
    val time_sqrt = sigma * Math.sqrt(time)
    val a = Math.log(S / K)
    val b = (r + sigma * sigma * 0.5f) * time
    val d1 = (a + b) / time_sqrt
    val d2 = d1 - time_sqrt
    (d1, d2)
  }
  
  /**
   * Black Scholes formula - Option Call.
   *
   * @param S     Spot price of underlying asset.
   * @param K     Strike (exercise) price.
   * @param r     Risk free rate (annual rate).
   * @param sigma Volatility
   * @param time  Time to maturity (remaining time, backwards time)
   */
  def optionPriceCall(S: Double, K: Double, r: Double, sigma: Double, time: Double): Double = {
    val (d1, d2) = optionPrice(S, K, r, sigma, time)
    S * N(d1) - K * Math.exp(-r * time) * N(d2)
  }

  /**
   * Black Scholes formula - Option Put.
   * <p>
   * P = C + K * Math.exp(-r * time) - S
   * 
   * @param S     Spot price of underlying asset.
   * @param K     Strike (exercise) price.
   * @param r     Risk free rate (annual rate).
   * @param sigma Volatility
   * @param time  Time to maturity (remaining time, backwards time)
   */
  def optionPricePut(S: Double, K: Double, r: Double, sigma: Double, time: Double): Double = {
    val (d1, d2) = optionPrice(S, K, r, sigma, time)
    S * (N(d1) - 1.0f) - K * Math.exp(-r * time) * (N(d2) - 1.0f)
  }

  /**
   * Price European Call Dividends
   *
   * An option that can only be exercised at the end of its life, at its maturity.
   * European options tend to sometimes trade at a discount to its comparable American option.
   * This is because American options allow investors more opportunities to exercise the contract.
   * European options normally trade over the counter, while American options usually trade on
   * standardized exchanges. A buyer of an European option that does not want to wait for maturity
   * to exercise it can sell the option to close the position.
   *
   * @param S               Spot price of underlying asset.
   * @param K               Strike (exercise) price.
   * @param r               Risk free rate (annual rate).
   * @param sigma           Volatility
   * @param time            Time to maturity
   * @param dividendTimes   Dividend times
   * @param dividendAmounts Dividend amounts
   */
  def optionPriceEuropeanCallDividends(S: Double,
                                       K: Double,
                                       r: Double,
                                       sigma: Double,
                                       time: Double,
                                       dividendTimes: Array[Double],
                                       dividendAmounts: Array[Double]) = {
    val adjustedS = dividendTimes.indices.
      filter(i => dividendTimes(i) <= time).
      foldLeft(S)((s, i) => s - dividendAmounts(i) * Math.exp(-r * dividendTimes(i)))
    optionPriceCall(adjustedS, K, r, sigma, time)
  }
  
  /**
   * Test Black Sholes formula
   */
  def main(args: Array[String]) = {
    // 5.6351
    println(optionPriceCall(210.59, 205.0, 0.2175/100.0, 14.04/100.0, 4.0/365.0))
    // 0.0402
    println(optionPricePut(210.59, 205.0, 0.2175/100.0, 14.04/100.0, 4.0/365.0))
  }
}
Convert an EAN (ISBN-13) to an ISBN-10 and vice versa.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
object Isbn {
  /**
   * Iterate over string characters.
   *
   * @param   s input string.
   * @param   f filter function.
   * @return  c callback function
   */
  def sumChars(s: String, f: (Int) => Boolean, c: (Int, Int, Char) => Int) = {
    s.indices.filter(i => f(i)).foldLeft(0)((sum, i) => c(sum, i, s charAt i))
  }

  /**
   * Convert an EAN (ISBN-13) to an ISBN-10
   *
   * @param ean the ISBN-13 code
   * @return the ISBN-10 code
   */
  def eanToIsbn(ean: String) = {

    def checksum(sum: Int) = sum match {
      case 10 => "X"
      case 11 => "0"
      case _  => sum toString
    }

    val isbn = ean substring (3, 12)
    val weight = 10

    val sum = sumChars(isbn, (i) => true, (sum, i, c) => sum + c.asDigit * (weight - i))

    isbn + checksum(11 - sum % 11)
  }

  /**
   * Convert an ISBN-10 code to an EAN (ISBN-13) code
   *
   * @param isbn the ISBN-10 code
   * @return the ISBN-13 (EAN) code
   */
  def isbnToEan(isbn: String) = {
    
    def isEven(i: Int) = i % 2 == 0

    val ean = ("978" + isbn) substring (0, 12)
    // sum odd digits
    val sumOdd = sumChars(ean, (i) => !isEven(i), (sum, i, c) => sum + c.asDigit)
    // sum even digits
    val sumEven = sumChars(ean, (i) => isEven(i), (sum, i, c) => sum + c.asDigit)

    val sum = sumOdd * 3 + sumEven
    val checksum = (10 - sum % 10) % 10

    ean + checksum
  }
}

Statistics formulas

Scala is also a solid option to implement statistics and financials formulas.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
object Statistics {
  /**
   * Returns the average (arithmetic mean) of the arguments.
   * 1/n * sum(x)
   *
   * @param data population
   * @return arithmetic mean
   */
  def avg(data: Array[Double]): Double = {
    if (data.length < 1)
      return Double.NaN
    //data.foldLeft(0.0)(_ + _) / data.length
    data.sum / data.length
  }

  /**
   * Calculates the standard deviation of an array
   * of numbers.
   * see http://davidmlane.com/hyperstat/A16252.html
   *
   * @param data Numbers to compute the standard deviation of.
   *             Array must contain two or more numbers.
   * @return standard deviation estimate of population
   *         ( to get estimate of sample, use n instead of n-1 in last line )
   */
  def stdev(data: Array[Double]): Double = {
    if (data.length < 2)
      return Double.NaN
    // average
    val mean: Double = avg(data)

    val sum = data.foldLeft(0.0)((sum, tail) => {
      val dif = tail - mean
      sum + dif * dif
    })

    Math.sqrt(sum / (data.length - 1))
  }

  /**
   * Calculates the standard deviation of an array of numbers.
   * see Knuth's The Art Of Computer Programming
   * Volume II: Seminumerical Algorithms
   * This algorithm is slower, but more resistant to error propagation.
   *
   * @param data Numbers to compute the standard deviation of.
   *             Array must contain two or more numbers.
   * @return standard deviation estimate of population
   *         ( to get estimate of sample, use n instead of n-1 in last line )
   */
  def stdevk(data: Array[Double]): Double = {
    if (data.length < 2)
      return Double.NaN

    val sum = data.indices.foldLeft((0.0, data(0)))((s, i) => {
      val dif = data(i) - s._1
      val avg = s._2 + dif / (i + 1)
      val sum = s._1 + dif * (data(i) - avg)
      (sum, avg)      
    })
    
    Math.sqrt(sum._1 / (data.length - 1))
  }

  /**
   * Returns the sum of squares of deviations of data points
   * from their sample mean.
   * sum((x - stdev)**2)
   *
   * @param data Numbers to compute
   * @return Returns the sum of squares of deviations
   *         of data points from their sample mean.
   */
  def devsq(data: Array[Double]): Double = {
    val sigma = stdev(data)

    data.foldLeft(0.0)((sum, tail) => {
      val dif = tail - sigma
      sum + dif * dif
    })
  }

  /**
   * 1/n * sum(1/x)
   *
   * @param data Numbers to compute
   * @return Returns the harmonic mean of a data set.
   *         The harmonic mean is the reciprocal
   *         of the arithmetic mean of reciprocals.
   */
  //5.028375962061728
  def harmean(data: Array[Double]): Double = {
    if (data.contains(0.0))
      return Double.NaN
    data.length / data.foldLeft(0.0)((s, t) => s + 1.0 / t)
  }

  /**
   * The central tendency or typical value of a set of numbers
   * by using the product of their values
   * (as opposed to the arithmetic mean which uses their sum).
   * The geometric mean is defined as the nth root
   * (where n is the count of numbers) of the product of the numbers.
   *
   * @param data Numbers to compute
   * @return Returns the geometric mean of an array
   *         or range of positive data.
   */
  def geomean(data: Array[Double]): Double = {
    if (data.length == 0)
      return 0.0
    //
    val prod = data.foldLeft(1.0)((s, t) => s * t)
    Math.pow(prod, 1.0f / data.length)
  }

  /**
   * Estimates variance based on a sample.
   *
   * @param data Numbers to compute
   * @return population variance
   */
  def variance(data: Array[Double]): Double = {
    if (data.length < 2)
      return Double.NaN
    val mean = avg(data)

    val sum = data.foldLeft(0.0)((sum, tail) => {
      val dif = tail - mean
      sum + dif * dif
    })
    sum / (data.length - 1)
  }

  /**
   * Standard deviation of the sampling distribution of a statistic
   *
   * @param data Numbers to compute
   * @return standard error
   */
  def stderr(data: Array[Double]): Double = {
    if (data.length < 1)
      return Double.NaN
    stdev(data) / Math.sqrt(data.length)
  }

  /**
   * 1/n * sum(abs(x - stdev))
   *
   * @param data Numbers to compute
   * @return Returns the average of the absolute deviations of data points from their mean.
   */
  def avedev(data: Array[Double]): Double = {
    if (data.length < 1)
      return Double.NaN
    val sigma = avg(data)
    data.foldLeft(0.0)((s, t) => s + Math.abs(t - sigma)) / data.length
  }

  /**
   * Returns covariance, the average of the products
   * of deviations for each data point pair
   *
   * @param x first population
   * @param y second population
   * @return covariance
   */
  def covar(x: Array[Double], y: Array[Double]): Double = {
    // the two arrays must have the same size
    if (x.length != y.length)
      return Double.NaN
    // calculate the means of the series
    val xm = avg(x)
    val ym = avg(y)
    // calculate covar
    val sum = x.indices.foldLeft(0.0)((sum, i) => sum + (x(i) - xm) * (y(i) - ym))
    // return the result
    sum / x.length
  }

  /**
   * Returns the correlation coefficient of the array1 and array2
   *
   * @param x first population
   * @param y second population
   * @return correlation
   */
  def correl(x: Array[Double], y: Array[Double]): Double = {
    // the two arrays must have the same size
    if (x.length != y.length)
      return Double.NaN
    // calculate the means of the series
    val xm = avg(x)
    val ym = avg(y)
    val (s1, s2, s3) = x.indices.foldLeft((0.0, 0.0, 0.0))((t, i) => {
      val xv = x(i) - xm
      val yv = y(i) - ym
      (t._1 + xv * yv, t._2 + xv * xv, t._3 + yv * yv)
    })
    // return the result
    s1 / Math.sqrt(s2 * s3)
  }

  /**
   * Returns the inverse of the standard normal cumulative distribution.
   *
   * @param data Numbers to compute
   * @return inverse of the standard normal cumulative distribution
   */
  def normsinv(data: Array[Double]): Double = {
    if (data.length < 1)
      return Double.NaN
    stdev(data) / Math.sqrt(data.length)
  }

  /**
   * In probability theory and statistics,
   * kurtosis (from the Greek word kyrtos or kurtos, meaning curved, arching)
   * is any measure of the "peakedness" of the probability
   * distribution of a real-valued random variable.
   *
   * @param data population
   * @return kurtosis
   */
  def kurt(data: Array[Double]): Double = {
    val n = data.length
    if (n < 4)
      return Double.NaN
    // standard deviation
    val sigma = stdev(data)
    if (sigma == 0)
      return Double.NaN
    // average
    val mean = avg(data)
    val sum = data.foldLeft(0.0)((sum, item) => {
      val v = (item - mean) / sigma
      val vv = v * v
      sum + (vv * vv)
    })
    // constants
    val k1 = 1.0f * n * (n + 1) / (n - 1) / (n - 2) / (n - 3)
    val k2 = 3.0f * (n - 1) * (n - 1) / (n - 2) / (n - 3)
    // kurtosis
    k1 * sum - k2
  }

  /**
   * In probability theory and statistics, skewness is a measure
   * of the extent to which a probability distribution of a real-valued
   * random variable "leans" to one side of the mean.
   * The skewness value can be positive or negative, or even undefined.
   *
   * @param data population
   * @return skewness
   */
  def skew(data: Array[Double]): Double = {
    val n = data.length
    if (n < 3)
      return Double.NaN
    // standard deviation
    val sigma = stdev(data)
    if (sigma == 0)
      return Double.NaN
    // average
    val mean = avg(data)
    val sum = data.foldLeft(0.0)((sum, item) => {
      val v = (item - mean) / sigma
      sum + (v * v * v)
    })
    // constants
    val k1 = 1.0f * n / (n - 1) / (n - 2)
    k1 * sum
  }

  /**
   * A common function used by slope, intercept, forecast
   * functions
   *
   * @param x first population
   * @param y second population
   * @param xm average value of first population
   * @param ym average value of second population
   * @return tuple of sum's
   */
  def common(x: Array[Double], y: Array[Double],
             xm: Double, ym: Double): (Double, Double) = {
    // init
    // calculate sum's
    x.indices.foldLeft((0.0, 0.0))((t, i) => {
      val xv = x(i) - xm
      val yv = y(i) - ym
      (t._1 + xv * yv, t._2 + xv * xv)
    })
  }

  /**
   * Returns the slope of the linear regression line through
   * data points in known_y's and known_x's.
   * The slope is the vertical distance divided by the
   * horizontal distance between any two points on the line,
   * which is the rate of change along the regression line.
   *
   * @param x first population
   * @param y second population
   * @return slope (b coefficient)
   */
  def slope(x: Array[Double], y: Array[Double]): Double = {
    if (x.length != y.length)
      return Double.NaN
    val xm = avg(x)
    val ym = avg(y)
    val (sum1, sum2) = common(x, y, xm, ym)
    // the b coefficient
    sum1 / sum2
  }

  /**
   * Calculates the point at which a line will intersect
   * the y-axis by using existing x-values and y-values.
   * The intercept point is based on a best-fit regression
   * line plotted through the known x-values and known y-values.
   * Use the INTERCEPT function when you want to determine the
   * value of the dependent variable when the independent variable is 0 (zero).
   * For example, you can use the INTERCEPT function to predict a
   * metal's electrical resistance at 0C when your data points
   * were taken at room temperature and higher.
   *
   * @param x first population
   * @param y second population
   * @return intercept
   */
  def intercept(x: Array[Double], y: Array[Double]): Double = {
    if (x.length != y.length)
      return Double.NaN
    val xm = avg(x)
    val ym = avg(y)
    val (sum1, sum2) = common(x, y, xm, ym)
    // the b coefficient
    val b = sum1 / sum2
    // intercept
    ym - xm * b
  }

  /**
   * Calculates, or predicts, a future value by using existing values.
   * The predicted value is a y-value for a given x-value.
   * The known values are existing x-values and y-values,
   * and the new value is predicted by using linear regression.
   * You can use this function to predict future sales, inventory
   * requirements, or consumer trends.
   *
   * @param p data point
   * @param x first population
   * @param y second population
   * @return forecast
   */
  def forecast(p: Double, x: Array[Double], y: Array[Double]): Double = {
    if (x.length != y.length)
      return Double.NaN
    // calculate the means of the series
    val xm = avg(x)
    val ym = avg(y)
    val (sum1, sum2) = common(x, y, xm, ym)
    // the b coefficient
    val b = sum1 / sum2
    // intercept
    val a = ym - xm * b
    a + b * p
  }

  /**
   * Srinivasa Ramanujan ln(n!) factorial estimation.
   * Good for larger values of n.
   *
   * @param n
   * @return ln(n!)
   */
  def factorialApproximation(n: Double): Double = {
    if (n < 2.0f)
      return 0.0f
    val a = n * Math.log(n) - n
    val b = Math.log(n * (1.0f + 4.0f * n * (1.0f + 2.0f * n))) / 6.0f
    a + b + Math.log(Math.PI) / 2.0f
  }

  /**
   * Calculates an approximation of the Poisson probability.
   *
   * @param mean - lambda, the average number of occurrences
   * @param observed - the actual number of occurences observed
   * @return ln(Poisson probability) - the natural log of the Poisson probability.
   */
  def poissonProbabilityApproximation(mean: Double, observed: Int) {
    val a = observed * Math.log(mean)
    a - mean - factorialApproximation(observed)
  }
}

Flag Counter