43
Comparing Haskell & Scala

Comparing Haskell and Scala

Embed Size (px)

Citation preview

Page 1: Comparing Haskell and Scala

Comparing Haskell & Scala

Page 2: Comparing Haskell and Scala

Martin Ockajak from Zürich

Software Engineer

@martin_ockajak

Page 3: Comparing Haskell and Scala

Outline

● Similarities

● Conceptual differences

● Haskell – extra features

● Scala – extra features

● Practical considerations

Page 4: Comparing Haskell and Scala

Similarities

Page 5: Comparing Haskell and Scala

Overview

● High-level functional language

● Product of programming language research● Haskell: Purely functional with strong side-effect handling

● Scala: Functional and object-oriented

● Automatic memory management

● Static type checking

● Type inference• Haskell: global, variant of Hindley-Milner

• Scala: local, arguments require type annotations

Page 6: Comparing Haskell and Scala

Expressions

● Everything is an expression producing a value

● No operators, only infix functions with symbolic names

● Haskell

let list = [1 + 2, 3]in list !! 0

(#%) :: String -> String(#%) x = x ++ "!"

● Scala

val list = List(1 + 2, 3)list(0)

def #%(x: String): String = x + "!"

Page 7: Comparing Haskell and Scala

Higher order functions

Functions as arguments and values

● Haskell

applyAndInc f x = f x + 1

double x = x * 2

applyAndInc double 3

● Scala

def applyAndInc(f: Int => Int, x: Int) = f(x) + 1

def double(x: Int): Int = x * 2

applyAndInc(double, 3)

Page 8: Comparing Haskell and Scala

Anonymous functions

Lambda expressions

● Haskell

map (\x -> x + 1) [1, 2, 3]

map (+ 1) [1, 2, 3]

● Scala

List(1, 2, 3) map(x => x + 1)

List(1, 2, 3) map(_ + 1)List(1, 2, 3) map(x => x + 1)

List(1, 2, 3) map(_ + 1)

// partial functionList(1, 2, "3") collect { case x: Int => x + 1 }

Page 9: Comparing Haskell and Scala

Currying

Partial function application

● Haskell

curried x y = x + y + 1

let partial = curried 1in partial 2

uncurried = uncurry curriedcurriedAgain = curry uncurried

● Scala

def curried(x: Int)(y: Int): Int = x + y + 1

val partial = curried(1) _partial(2)

val uncurried = Function.uncurried(curried _)val curriedAgain = uncurried.curried

Page 10: Comparing Haskell and Scala

Encapsulation

Modules and access modifiers

● Haskell

module Module (foo) where

foo x = bar x + 1

bar x = x * 2

● Scala

object Encapsulation { def foo(x: Int) = bar(x) + 1

private def bar(x: Int) = x * 2}

Page 11: Comparing Haskell and Scala

Pattern matching with guards

● Haskell

factorial 0 = 1factorial n = n * factorial (n - 1)

pattern :: [Int] -> Intpattern l | [x] <- l, x /= 0 = 1 | length l > 1 = 2 | otherwise = 0

● Scala

def factorial(n: Int): Int = n match { case 0 => 1 case n => n * factorial(n - 1)}

def pattern(l: List[Int]): Int = l match { case List(x) if x != 0 => 1 case l if l.size > 1 => 1 case _ => 0}

Page 12: Comparing Haskell and Scala

List comprehensions

● Haskell

[ (x, y) | x <- [1, 2, 3], y <- [4, 5, 6], x * y > 7 ]

[0 | _ <- [1..10] ]

● Scala

for { x <- List(1, 2, 3) y <- List(4, 5, 6) if x * y > 7} yield (x, y)

for (_ <- List(1 to 10)) yield 0

Page 13: Comparing Haskell and Scala

Monadic composition notation

● Haskell

do x <- [1, 2, 3] y <- [4, 5, 6] let z = (x + y) return z

● Scala

for { x <- List(1, 2, 3) y <- List(4, 5, 6) z = x + y} yield z

Page 14: Comparing Haskell and Scala

Type system

● Parametric polymorphism

● Ad hoc polymorphism● Haskell: Typeclasses

● Scala: Typeclasses, method overloading, subtyping

● Generalized algebraic data types

● Multi-parameter type classes● Functional dependencies

Page 15: Comparing Haskell and Scala

Type system

● Compound types

● Type aliases

● Existential types

● Higher order types● Kinds

Page 16: Comparing Haskell and Scala

Algebraic data types

● Haskell

data Tree a = Empty | Node a (Tree a) (Tree a)

● Scala

sealed trait Tree[A]

case class Empty[A]() extends Tree[A]

case class Node[A](value: A, left: Tree[A], right: Tree[A]) extends Tree[A]

Page 17: Comparing Haskell and Scala

Typeclasess● Haskell

class Equals a where eq :: a -> a -> Bool

instance Equals Integer where eq x y = x == y

tcEquals :: (Equals a) => a -> a -> BooltcEquals a b = eq a b

● Scala

trait Equals[T] { def eq(x: T, y: T): Boolean}

implicit object EqualsInt extends Equals[Int] { override def eq(x: Int, y: Int): Boolean = x == y}

def tcEquals[T: Equals](x: T, y: T): Boolean = implicitly[Equals[T]].eq(x, y)

Page 18: Comparing Haskell and Scala

Additional features

● Implicit parameters

● Annotations

● Compile-time metaprogramming● Haskell: Template Haskell

● Scala: Macros

Page 19: Comparing Haskell and Scala

Conceptual Differences

Page 20: Comparing Haskell and Scala

Purity

● Haskell● Referential transparency● Side effects modeled via monads● Functions are pure

● Scala● No referential transparency guarantees● Side effects allowed anywhere● Functions cannot be considered pure

Page 21: Comparing Haskell and Scala

Default evaluation strategy

● Haskell● Non-strict lazy evaluation● Optional eager evaluation

● Bang patterns● Strict modules

● Scala● Strict eager evaluation● Optional lazy evaluation

● Call-by-name parameter with lazy val pattern

Page 22: Comparing Haskell and Scala

Control flow

● Haskell● Completely declarative● Exception handling via monads● No way to jump off current scope

● Scala● Imperative constructs are supported● Exception handling at language level● Early return from a method

Page 23: Comparing Haskell and Scala

Haskell – extra features

Page 24: Comparing Haskell and Scala

Pointfree style

● Omitting arguments in function definition

-- Point-wise

incp x = x + 1

expp x = 1 + 2 * x

-- Pointfree

incf = (+ 1)

expf = (1 +) . (2 *)

Page 25: Comparing Haskell and Scala

Polymorphic string literals

● String syntax for various string-like types

string1 :: String

string1 = "string"

string2 :: Text

string2 = "text"

"test" :: IsString a => a

class IsString a where

fromString :: String -> a

Page 26: Comparing Haskell and Scala

Extended list comprehensions

● Parallel (zip)[ (x, y) | x <- [1, 2, 3] | y <- [4, 5, 6]]

● Transformcities = [ ("Berlin", 4.1), ("Milan", 5.2), ("Zurich", 1.3) ]

[ name ++ "!" | (name, size) <- cities,

then sortWith by size,

then drop 1 ]

● Monad[ x + y | x <- Just 1, y <- Just 2 ]

Page 27: Comparing Haskell and Scala

Deriving typeclass instances

● Typeclasses: Eq, Ord, Enum, Bounded, Show, Read

data Coordinate = Planar Float Float | Spatial Float Float Float deriving (Eq, Ord, Show)

Planar 1 2 == Planar 1 2

Spatial 1 2 1 < Spatial 1 2 3

show (Planar 1 2)

Page 28: Comparing Haskell and Scala

Higher rank polymorphism

● Polymorphic function argument specified by the callee

id :: a -> a

id x = x

rank1 :: forall a. a -> a

rank1 x = x

rank2 :: (forall a. Num a => a -> a) -> (Int, Float)

rank2 f = (f 1, f 1.0)

rank2 (* 2)

Page 29: Comparing Haskell and Scala

Compiler extensions

● View patterns & pattern synonyms● Type families● Data type generic programming● Kind polymorphism● And many more …

Page 30: Comparing Haskell and Scala

Scala – extra features

Page 31: Comparing Haskell and Scala

Imperative programming

● Mutable state● Code blocks● While loops

var mutable = 1mutable = 2

while (mutable < 3) { List(1, 2, 3).foreach(_ => println("Missile fired")) mutable += 1}

throw new IllegalStateException("Abandon ship")

Page 32: Comparing Haskell and Scala

Object-oriented programming

● Subtyping● Type variance, type bounds

● Class-based inheritance system● Classes, traits, objects, abstract type members

● Mixin class composition● Multiple inheritance with traits, self-typed references

Page 33: Comparing Haskell and Scala

Named and default arguments

● Just like in Python

def very(standard: String, default: String = "value"): Unit = ()

very("text")

def handy(default: String = "value", standard: String): Unit = ()

handy(standard = "text")

Page 34: Comparing Haskell and Scala

String interpolation

● Programmable via custom interpolators

val neat = 7

// standard libraryval substitution = s"Is $neat"

val printf = f"Number is $neat%02d"

val noEscaping = raw"some\nthing"

// external libraryval document = json"""{ "hello": "world" }"""

Page 35: Comparing Haskell and Scala

Flexible scoping

● Fields in traits● Abstract members● Nested function definitions● Multiple classes & objects in one source file

trait FlexibleScoping { def abstractMethod(text: String): String

val abstractField: Int

def get: String = { def compute: String = "result"

abstractMethod(compute) }}

Page 36: Comparing Haskell and Scala

Implicit conversion

● Automated conversion of method arguments● Searches in current and various outer scopes● Method argument is converted using the implicit method

def more(value: Int): Int = 2 * value

implicit def convert(value: Vector[_]): Int = value.size

more(Vector(1, 2, 3))

// equivalent call with explicit conversionmore(convert(Vector(1, 2, 3)))

Page 37: Comparing Haskell and Scala

Structural typing

● Type checking based on type contents not its name● Resolved at compile-time as opposed to duck-typing

def oneMore(countable: { def size: Int }): Unit = { countable.size + 1}

oneMore(List(1, 2, 3))

Page 38: Comparing Haskell and Scala

Dynamic typing

● Programmable late binding at run-time

import scala.language.dynamics

object Accepts extends Dynamic { def selectDynamic(name: String): Int = name.size

def applyDynamic(name: String)(args: Any*): String = name}

Accepts.something

Accepts.hello("World")

Page 39: Comparing Haskell and Scala

Type system features

● Type lambdas

● F-bounded types● Self-recursive types

● Path-dependent types● Instance bound types

● Value classes

● Type specialization

Page 40: Comparing Haskell and Scala

Practical considerations

Page 41: Comparing Haskell and Scala

Practicality - Haskell

● Great productivity

● High runtime performance

● Clever community

● Solid library and tooling ecosystem

● Reasoning about can be tricky

● Steep learning curve (real or imagined)

Page 42: Comparing Haskell and Scala

Practicality - Scala

● Great productivity

● High runtime performance

● Clever community

● Largest library and tooling ecosystem

● Easy to transition from Java, C++, C#

● Java interoperability somewhat pollutes the language

Page 43: Comparing Haskell and Scala

Thank you :-)