O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

Comparing Haskell and Scala

2.574 visualizações

Publicada em

Both Haskell and Scala are very expressive functional programming languages which are undergoing active development.

We will look at fundamental concepts and goals which inspired their design. We will examine similarities and differences between various features of these languages using code examples. We will also attempt to briefly assess their practicality in software engineering context.

Publicada em: Software

Comparing Haskell and Scala

  1. 1. Comparing Haskell & Scala
  2. 2. Martin Ockajak from Zürich Software Engineer @martin_ockajak
  3. 3. Outline ● Similarities ● Conceptual differences ● Haskell – extra features ● Scala – extra features ● Practical considerations
  4. 4. Similarities
  5. 5. 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
  6. 6. 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 + "!"
  7. 7. 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)
  8. 8. 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 function List(1, 2, "3") collect { case x: Int => x + 1 }
  9. 9. Currying Partial function application ● Haskell curried x y = x + y + 1 let partial = curried 1 in partial 2 uncurried = uncurry curried curriedAgain = 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
  10. 10. 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 }
  11. 11. Pattern matching with guards ● Haskell factorial 0 = 1 factorial n = n * factorial (n - 1) pattern :: [Int] -> Int pattern 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 }
  12. 12. 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
  13. 13. 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
  14. 14. Type system ● Parametric polymorphism ● Ad hoc polymorphism ● Haskell: Typeclasses ● Scala: Typeclasses, method overloading, subtyping ● Generalized algebraic data types ● Multi-parameter type classes ● Functional dependencies
  15. 15. Type system ● Compound types ● Type aliases ● Existential types ● Higher order types ● Kinds
  16. 16. 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]
  17. 17. Typeclasess ● Haskell class Equals a where eq :: a -> a -> Bool instance Equals Integer where eq x y = x == y tcEquals :: (Equals a) => a -> a -> Bool tcEquals 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)
  18. 18. Additional features ● Implicit parameters ● Annotations ● Compile-time metaprogramming ● Haskell: Template Haskell ● Scala: Macros
  19. 19. Conceptual Differences
  20. 20. 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
  21. 21. 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
  22. 22. 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
  23. 23. Haskell – extra features
  24. 24. Pointfree style ● Omitting arguments in function definition -- Point-wise incp x = x + 1 expp x = 1 + 2 * x -- Pointfree incf = (+ 1) expf = (1 +) . (2 *)
  25. 25. 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
  26. 26. Extended list comprehensions ● Parallel (zip) [ (x, y) | x <- [1, 2, 3] | y <- [4, 5, 6]] ● Transform cities = [ ("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 ]
  27. 27. 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)
  28. 28. 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)
  29. 29. Compiler extensions ● View patterns & pattern synonyms ● Type families ● Data type generic programming ● Kind polymorphism ● And many more …
  30. 30. Scala – extra features
  31. 31. Imperative programming ● Mutable state ● Code blocks ● While loops var mutable = 1 mutable = 2 while (mutable < 3) { List(1, 2, 3).foreach(_ => println("Missile fired")) mutable += 1 } throw new IllegalStateException("Abandon ship")
  32. 32. 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
  33. 33. 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")
  34. 34. String interpolation ● Programmable via custom interpolators val neat = 7 // standard library val substitution = s"Is $neat" val printf = f"Number is $neat%02d" val noEscaping = raw"somenthing" // external library val document = json"""{ "hello": "world" }"""
  35. 35. 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) } }
  36. 36. 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 conversion more(convert(Vector(1, 2, 3)))
  37. 37. 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))
  38. 38. 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")
  39. 39. Type system features ● Type lambdas ● F-bounded types ● Self-recursive types ● Path-dependent types ● Instance bound types ● Value classes ● Type specialization
  40. 40. Practical considerations
  41. 41. 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)
  42. 42. 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
  43. 43. Thank you :-)

×