• Stars
    star
    2
  • Language
    Scala
  • License
    Apache License 2.0
  • Created almost 6 years ago
  • Updated almost 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Scala case study about building an interpreter and a simple DSL.

Interpreter Case Study

WIP: Case study building a mini interpreter for a simple DSL.

  1. Untyped DSLs

a. Build a simple DSL representing: numbers, addition, and multiplication

i. Build an ADT Expr representing an expression

// 1 * 2 + 3 * 4
val expr: Expr = Add(Mul(Lit(1), Lit(2)),
                     Mul(Lit(3), Lit(4)))

ii. Build an interpreter to run expressions:

def eval(expr: Expr): Int

iii. Make your interpreter generic in some F[_] (hint: what is F? a monad? a functor? an applicative? this will change from exercise to exercise)

b. Add some features that require error handling:

  • booleans as well as numbers
  • boolean operators (<= and && at minimum)

i. Add some terms to your Expr type

// 1 < 2 && 3 < 4
// And(Lt(Lit(1), Lit(2)), Lt(Lit(3), Lit(4)))
// Lt(Lt(Lit(1), Lit(2)), Lt(Lit(3), Lit(4)))

ii. Update your interpreter to handle the new types - how to represent the different types expressions can calculate? - Value type - what kinds of errors can happen now? - try to treat Value as Int / Boolean - the interpreter will need some error handling - ApplicativeError or MonadError

class Interpreter[F[_]: ApplicativeError[?[_], String]] {
  def eval(expr: Expr): F[Value] = ???

  // def asInt(value: Value): F[Int] = ???
  // def asBoolean(value: Value): F[Boolean] = ???

  def evalAsInt(expr: Expr): F[Int] =
    eval(expr).flatMap {
      case IntVal(i)  => i.pure[F]
      case BoolVal(b) => s"Expected integer, received $b".raiseError[F, Int]
    }

  def evalAsBool(expr: Expr): F[Boolean] =
    eval(expr).flatMap {
      case IntVal(i)  => s"Expected boolean, received $i".raiseError[F, Boolean]
      case BoolVal(b) => b.pure[F]
    }
}

c. If you have time, add some more interesting expression types:

  • conditionals
  • logging statements
  • blocks

Aside on kind projector and type lambdas

type ErrorOr[A] = Either[String, A]
Monad[ErrorOr]

Monad[Either[String, ?]]

Monad[({ type ErrorOr[A] = Either[String, A] })#ErrorOr]

type AsyncErrorOr[A] = EitherT[Future, String, A]

MonadError[Future, Throwable]
MonadError[ErrorOr, String]
MonadError[AsyncErrorOr, String]

Typed DSLs

The interpreter is probably quite complex by now. We can make it simpler using Scala's type system.

a. Convert your untyped DSL to a typed DSL

i. Add a type parameter to Expr:

sealed trait Expr[A]

ii. Your interpreter now becomes:

def eval[F[_], A](expr: Expr[A]): F[A]

The interpreter should need less error handling. Can you downgrade from an (Applicative|Monad)Error to an (Applicative|Monad)?

Monadic DSLs

So far, the interpreter has dictated the order in which statements are executed. We can hand this control over to the user if we make Expr a monad.

a. Add a new type of Expr called FlatMapExpr.

// The flatMap method on a Monad looks like this:
new Monad[Expr] {
  def flatMap[A, B](fa: Expr[A])(f: A => Expr[B]): Expr[B]
}

// We *reify* that to a data structure
// so we can evaluate it in our interpreter later:
case class FlatMapExpr[A, B](fa: Expr[A], f: A => Expr[B]) extends Expr[B]

b. Create map and flatMap methods for Expr, either by writing them directly or by creating a Monad instance for Expr.

c. We now have FlatMapExpr to specify ordering. We don't need to nest other types of Expr:

// Your existing case class
case class Add(l: Expr[Int], r: Expr[Int]) extends Expr[Int]

// Can be rewritten as something simpler:
case class Add(l: Int, r: Int) extends Expr[Int]

d. Any programs in the DSL now have to be written as for comprehensions:

for {
  a <- Lit(1) : Expr[Int]
  b <- Lit(2)
  c <- Add(a, b)
} yield c

Tagless DSL/Interpreter

trait Expr[F[_]] {
  def add(x: Int, y: Int): F[Int]
  def mul(x: Int, y: Int): F[Int]
  def lt(x: Int, y: Int): F[Boolean]
  def and(x: Boolean, y: Boolean): F[Boolean]
}

trait KeyValueStore[F[_]] {
  def get(key: String): F[Int]
  def set(key: String, value: Int): F[Unit]
}

class Program[F[_], G[_]](expr: Expr[F], store: KeyValueStore[G])(
  implicit
  monad: Monad[F],
  transform: F ~> G
) {
  import expr._
  import store._

  def run: F[Int] =
    for {
      a <- transform(1.pure[F])
      b <- transform(2.pure[F])
      c <- transform(add(a, b))
      _ <- set("temp", c)
      d <- get("temp")
    } yield d
}

More Repositories

1

bridges

Generate bindings for Scala types in other programming languages.
Scala
56
star
2

checklist

Validation library for Scala.
Scala
47
star
3

unindent

Indent-adjusted multiline string literals for Scala.
Shell
47
star
4

bulletin

Automatically perform shallow merges on case classes. Treat your data with the latest updates!
Scala
42
star
5

meowsynth

The mighty meowing synthesizer!
Scala
30
star
6

validation

Scala data validation library
Scala
29
star
7

typelevel-todomvc

Scala
25
star
8

atlas

A tiny embedded scripting language implemented in Scala.
Scala
24
star
9

shapeless-guide

The Type Astronaut's Guide to Shapeless
19
star
10

functional-data-validation

Slides and code samples for a talk on thinking functionally (and validating web forms).
Scala
18
star
11

99-ways-to-di

Slides from my lightning talk on Dependency Injection at Scala Central #5.
14
star
12

css-selector

Lift-style CSS selector transforms based on Scalate's Scuery
Scala
10
star
13

tipi

Tiny templating language written in Scala.
Scala
10
star
14

macros-vs-shapeless

Slides and code samples on meta-programming techniques in Scala.
Scala
10
star
15

spandoc

Write Pandoc filters in Scala.
Scala
7
star
16

scalalol-2011-talk

Slides and code samples for talk at Scala Lift-Off London 2011.
Scala
6
star
17

scala-opengl

Simple OpenGL examples using Scala, LWJGL, and sbt-lwjgl
Scala
6
star
18

shapeless-guide-slides

Slides for my Scala World 2016 workshop on shapeless.
6
star
19

smartypants

Simple smart constructor generation for Scala.
Scala
4
star
20

scalax2gether-2017

Workshop and hack proposals for the Scala Exchange Hack Day (ScalaX2gether 2017)
4
star
21

shapeless-sandbox

Scala
3
star
22

scalax-2014

Slides and code samples for my Scala Exchange 2014 talk on Functional Data Validation.
3
star
23

typelevel-philly-2016

3
star
24

sbt-less

Superseded by sbt-less in https://github.com/untyped/sbt-plugins.
Scala
3
star
25

akka-streams-case-study

Scala
2
star
26

poker-case-study

Poker hand comparison in Scala. A fairly advanced "Essential Scala" case study.
Scala
2
star
27

cats-error-case-study

Scala
2
star
28

bus-driver-case-study

Gossiping Bus Drivers Kata
Scala
2
star
29

concurrency-case-study

Scala
2
star
30

scala-rpg-test

A sandbox project for playing with Scala and the graphics from Browserquest.
Scala
2
star
31

versionit

Grab your Git commit hash as a Scala String.
Scala
2
star
32

advanced-scala-scalax15

Code written at Advanced Scala at Scala Exchange 2015
Scala
1
star
33

spectaskular-iphone

iPhone todo list app
Objective-C
1
star
34

brighton-java-sample-app

Scala talk for Brighton Java
CSS
1
star
35

session-cell

Cookie-based in-memory session storage for the Racket HTTP Server.
Scheme
1
star
36

kitties-case-study

Meow!
Scala
1
star
37

gilded-rose-case-study

Code refactoring kata
Scala
1
star
38

conway-case-study

Scala
1
star
39

mars-rover-case-study

Scala
1
star
40

asyncjs-creative-fp

Creative Functional Programming talk for AsyncJS.
1
star
41

parallel-case-study

Scala
1
star
42

bank-ocr-case-study

Scala
1
star
43

play-json-case-study

Scala
1
star
44

calc-case-study

Scala
1
star
45

bowling-case-study

Scala
1
star
46

paths-case-study

Essential Scala case study: selecting paths from a route finder service
Scala
1
star
47

typeclub

Scala
1
star
48

tagless-case-study

Scala
1
star
49

doodlejs

Javascript port of Doodle
JavaScript
1
star
50

composejs

Javascript port of Compose (https://github.com/underscoreio/compose).
JavaScript
1
star
51

fpinscala

My attempts at the exercises in Functional Programming in Scala.
Scala
1
star
52

shapeless-guide-code

The Type Astronaut's Guide to Shapeless (Example Code)
1
star
53

scaladays-berlin-2016

1
star
54

property-based-testing-workshop

Scala
1
star
55

advanced-scala-exercises

Scala
1
star
56

advanced-scala

The old source code repository for Scala with Cats
1
star
57

cats-effect-sandbox

An empty SBT project with dependencies on Cats and Cats Effect.
Scala
1
star
58

away-with-the-types

Scala
1
star