all aboard the scala-to-purescript express!
TRANSCRIPT
All Aboard the Scala-to-PureScript
Express!John A. De Goes
What's Wrong with Scala?Nothing... Scala Makes FP Possible
What's Wrong with Scala?PureScript Makes FP Easy
• Syntax optimized for function definition & application
• Polymorphic functions
• Rank-n types
• Higher-kinded type inference
• Constraint inference
• Polymorphic row types (records, effects)
• Effect system for high performance, good reasoning
What's Wrong with Scala?PureScript Is Just Like Scala!
• Strict, not lazy
• Good mapping of primitives to JVM
• Integer -> int, java.lang.Integer
• Number -> float, java.lang.Float
• String -> String1
• Boolean -> boolean, java.lang.Boolean
• Array a -> Java array
• Java-compatible FFI
• Import types
• Import (static) functions
• No story for methods
• Wrap, baby, wrap!
In Fact, The Core of Scala is... PureScript!
1 Not [Char] like Haskell!
PureScript TourComments
// Single-line/* Multi-line *//** Scala doc */
-- Single-line(* Multi-line *)-- | PureScript doc
PureScript TourLiterals
val bool = true -- Booleanval int = 2 -- Integerval float = 2.2 -- Floatval char = 'C' -- Charval string = "foo" -- Stringval tuple = (1, 2) -- Tuple2
let bool = true -- Booleanlet int = 2 -- Intlet float = 2.2 -- Numberlet char = 'C' -- Charlet string = "foo" -- Stringlet array = [1, 2] -- Array Intlet record = {a: 1} -- Record
PureScript TourLocal Variables (Let)
val dsquared = d * dval distance = Math.sqrt(dsquared)distance * 0.5
let dsquared = d * d distance = sqrt distancein distance * 0.5
PureScript TourLocal Variables (Where)
halfDistance d = distance * 0.5 where dsquared = d * d distance = sqrt distance
PureScript TourData: Products
case class Person(name: String, age: Int) | Type constructor
// Implicit data constructor:// object Person { def apply(name: String, age: Int): Person = new Person(name, age) }
data Person = Person String Int | |Type Constructor Data Constructor
PureScript TourData: Products w/Records
val sherlock = Person("Sherlock Holmes", 42)
let sherlock = Person "Sherlock Holmes" 42
PureScript TourData: Products w/Records
data Person = Person {name :: String, age :: Int}
let sherlock = Person {name: "Sherlock Holmes", age: 42}
PureScript TourData: Sums
sealed trait Option[A]final case class Some[A](value: A) extends Option[A]final case class None[A]() extends Option[A]
data Option a = Some a | None
PureScript TourData: Sums
val somePerson: Option[Person] = Some(sherlock)
let somePerson = Some sherlock
PureScript TourPattern Matching: Products
val name = sherlock match { case Person(name, age) => name}
let name = case sherlock of Person name age -> name
PureScript TourPattern Matching: Records
let name = case sherlock of Person {name: n, age: a} -> n
PureScript TourPattern Matching: Sums
val name = somePerson match { case Some(Person(name, _)) => name case None() => "Mary Smith"}
let name = case somePerson of Some (Person name _) -> name None -> "Mary Smith"
PureScript TourPattern Matching: Sums (w/Records)
let name = case somePerson of Some (Person {name: name}) -> name None -> "Mary Smith"
PureScript TourTypes: Signatures (Definitions)
val nameExtractor : Person => String = _.name
nameExtractor :: Person -> StringnameExtractor (Person name _) = name
PureScript TourTypes: Signatures (Inline)
val i = 3(i * (2 : Int)) + 5
PureScript TourTypes: Signatures (Inline)
let i = 3 in (i * (2 :: Int)) + 5
PureScript TourTypes: Aliases
type Result[A] = Either[Error, A]
type Email = String
type Function[A, B] = A => B
type Result a = Either Error a
type Email = String
type Function a b = a -> b
PureScript TourTypes: Records
type Person = { name :: String, age :: Int }
PureScript TourTypes: Arrays
let intArray = [1, 2, 3] -- Array Int
PureScript TourFunction Definition: Monomorphic
val squareIt : Float => Float = (x: Float) => x * x
squareIt :: Number -> NumbersquareIt x = x * x
PureScript TourFunction Definition: Monomorphic (Lambdas)
squareIt :: Number -> NumbersquareIt = \x -> x * x
PureScript TourFunction Definition: Polymorphic
def second[A, B](tuple: (A, B)): B = tuple._2
second :: forall a b. Tuple a b -> bsecond (Tuple _ b) = b
PureScript TourFunction Definition: Higher Arity
def fullName(firstName: String, lastName: String): String = firstName + " " + lastName
val result = fullName("John", "Doe")
fullName :: String -> String -> StringfullName first last = first <> " " <> last
result = fullName "John" "Doe"
PureScript TourFunction Definition: Higher Arity
myFunction :: a -> b -> c -> d -> e
-- Equivalent to:myFunction :: a -> (b -> (c -> (d -> e)))
PureScript TourFunction Application: Monomorphic
val squareIt : Float => Float = (x: Float) => x * x
squareIt(2.2)
squareIt :: Number -> NumbersquareIt = \x -> x * x
result = squareIt 2.2
PureScript TourPackages / Modules
package collections.immutable.list
// ...
module Collections.Immutable.List where
-- ...
PureScript TourImports
package collections.immutable.list
import scalaz.(IList)
module Collections.Immutable.List where
-- No wildcardimport Data.Tuple(Tuple(..))
PureScript TourExports
package object utils { public def second[A, B](tuple: (A, B)) B = tuple._2}
module Util (second) where import Data.Tuple(Tuple(..))
second :: forall a b. Tuple a b -> b second (Tuple _ b) = b
PureScript TourType Classes
trait Semigroup[A] { def append(a1: A, a2: A): A}
implicit val StringSemigroup: Semigroup[String] { def append(a1: String, a2: String): String = a1 + a2}
class Semigroup a where append :: a -> a -> a
instance stringSemigroup :: Semigroup String where append a1 a2 = a1 <> a2
PureScript Tour(Sync|Async) Effects
println("What is your name?")val name = readLine()println("Hello, " + name "!")
prints = do println "What is your name?" name <- readLine println ("Hello, " <> name <> "!")
PureScript TourEffects
• No need to understand the monadic basis to get started
• Utilizes PureScript's polymorphic row types
• Different types of effects are labeled differently in a row of effects
• Fine-grained effect tracking without performance overhead
THE END