Slide 1

Slide 1 text

What Haskell can learn from Scala Lars Hupel Miles Sabin October 9th, 2015

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

What is Scala? To many Haskellers, Scala seems odd. 4

Slide 5

Slide 5 text

What is Scala? To many Haskellers, Scala seems odd. Scala is not: ▶ a better Java ▶ a worse Haskell 4

Slide 6

Slide 6 text

What is Scala? To many Haskellers, Scala seems odd. Scala is not: ▶ a better Java ▶ a worse Haskell ... it has unique strengths and weaknesses 4

Slide 7

Slide 7 text

What is Scala? To many Haskellers, Scala seems odd. Scala is not: ▶ a better Java ▶ a worse Haskell ... it has unique strengths and weaknesses 4

Slide 8

Slide 8 text

First Class Citizens “ Inprogramminglanguagedesign,afirst-classcitizen[...] isanentity whichsupportsalltheoperationsgenerallyavailabletootherentities. Theseoperationstypicallyincludebeingpassedasanargument,returned fromafunction,andassignedtoavariable. Wikipedia ” 5

Slide 9

Slide 9 text

Encoding of Type Classes class Ord a where (<=) :: a -> a -> Bool trait Ord[A] { def lte(a1: A, a2: A): Boolean } 6

Slide 10

Slide 10 text

Encoding of instances instance Ord a => Ord (List a) where [] <= [] = -- ... object Ord { implicit def list[A](implicit A: Ord[A]) = new Ord[List[A]] { // ... } } 7

Slide 11

Slide 11 text

Classes & Instances are First Class We have the full power of the language to manipulate them. trait Ord[A] { def lte(a1: A, a2: A): Boolean def flip: Ord[A] = new Ord[A] { // ... } } 8

Slide 12

Slide 12 text

Coherence? Confluence? Uniqueness? Contrary to popular belief: ▶ the implicitscope in Scala is well-defined ▶ many libraries restrict implicits to companionobjects ▶ ... which is equivalent to Haskell’s no-orphan policy ▶ “duplicate” instances are usually non-implicit 9

Slide 13

Slide 13 text

Observations 1. Use companions as much as possible. 2. Orphans are fine, as long as they are hidden behind an import. 3. Avoid newtypes.* 10

Slide 14

Slide 14 text

Language extensions for free Because typeclasses are classes, we can use OOP features! overriding default super classes mixins minimal complete definitions factories default signatures 11

Slide 15

Slide 15 text

Language extensions for free Because typeclasses are classes, we can use OOP features! overriding default super classes mixins minimal complete definitions factories default signatures 11 It looks like you’re using design patterns. Need the Gang of Four book?

Slide 16

Slide 16 text

Standard ML ▶ developed in the 1970s/80s ▶ main application domain: theorem proving ▶ type inference, garbage collection, algebraic data types, references ▶ module: named collection of values and types, possibly abstract ▶ functor: module → module 12

Slide 17

Slide 17 text

Functors signature KEY = sig type key val ord: key * key -> order end signature TABLE = sig type key type ’a table val empty: ’a table val insert: key * ’a -> ’a table -> ’a table end 13

Slide 18

Slide 18 text

Functors signature KEY = sig type key val ord: key * key -> order end functor Table(Key: KEY): TABLE = struct type key = Key.key datatype ’a table = (* some tree *) val empty = [] fun insert (k, v) table = (* ... *) Key.ord (* ... *) end 13

Slide 19

Slide 19 text

Functors signature KEY = sig type key val ord: key * key -> order end structure Int_Key: KEY = struct type key = int val ord = int_ord end structure Inttab = Table(Int_Key) (* usage *) Inttab.empty 13

Slide 20

Slide 20 text

Applicative vs. Generative Pop Quiz: Are these two types constructors compatible? structure Inttab1 = Table(Int_Key) structure Inttab2 = Table(Int_Key) Inttab1.table (* vs. *) Inttab2.table 14

Slide 21

Slide 21 text

Functors in Scala trait Key[K] { def ord(k1: K, k2: K): Order } trait Tables[K] { type Table[V] def empty[V]: Table[V] def union[V](t1: Table[V], t2: Table[V]): Table[V] } 15

Slide 22

Slide 22 text

Enforcing barriers val IntTables = Tables.fromImplicit[Int] val IntTablesRev = Tables(Key[Int].flip) /* only compiles if t1 and t2 belong to IntTables */ IntTables.union(t1, t2) 16

Slide 23

Slide 23 text

Enforcing barriers val IntTables = Tables.fromImplicit[Int] val IntTablesRev = Tables(Key[Int].flip) /* only compiles if t1 and t2 belong to IntTables */ IntTables.union(t1, t2) Uniqueness not required! 16

Slide 24

Slide 24 text

Generic Programming ▶ polymorphism: abstracting over types ... easy! ▶ generic programming: abstracting over data ▶ many use cases: ▶ Scrap Your Boilerplate ▶ automatic lenses ▶ parsing & pretty printing ▶ instance derivation 17

Slide 25

Slide 25 text

Recursive types data List a = Nil | Cons a (List a) How does deriving Eq proceed? 18

Slide 26

Slide 26 text

Recursive types data List a = Nil | Cons a (List a) How does deriving Eq proceed? Nil == Nil = True Cons x xs == Cons y ys = x == y && _ 18

Slide 27

Slide 27 text

Compiler support 19

Slide 28

Slide 28 text

... or library support Shapeless to the rescue! implicit def eqCons[A](implicit L: Lazy[Eq[List[A]]]) : Eq[Const[A]] = ??? implicit def eqList[A](implicit C: Lazy[Eq[Cons[A]]]) : Eq[List[A]] = ??? 20

Slide 29

Slide 29 text

Metaprogramming Many ecosystems have it, even Haskell ... Examples ▶ lens derive lenses for fields of a data type ▶ yesod templating, routing ▶ invertible-syntax constructing partial isomorphisms for constructors 21

Slide 30

Slide 30 text

Scala Macros There could be multiple talks comparing Template Haskell and Scala Macros ... Bottom line: ▶ macros look like regular Scala functions ▶ full power: may access network, file system, ... ▶ transparent: calls look like regular function calls, evaluated by compiler 22

Slide 31

Slide 31 text

“Transparent macros” if (a === b) 999 else 0 ↓ if (Eq.EqOps(a)(Eq.intEq).===(b)) 999 else 0 ↓ if (Eq.intEq.eqv(a, b)) 999 else 0 23

Slide 32

Slide 32 text

Ecosystem cabal vs. SBT 24

Slide 33

Slide 33 text

Ecosystem ≈ 684k ≈ 430k 24

Slide 34

Slide 34 text

Law Checking ▶ type classes are used pervasively in both Haskell & Scala ▶ most of them come equipped with laws ▶ ... some even with rather complicated ones 25

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

Law Checking ▶ type classes are used pervasively in both Haskell & Scala ▶ most of them come equipped with laws ▶ ... some even with rather complicated ones ▶ managing laws becomes important 28

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

Q & A  larsr h  larsrh