Your Program Is a Language - Examples
Demo examples given during Your Program Is A Language at ScalaCon Fall 2021.
Examples are written in Scala 3 and Scala 2.
Scala 2 examples are found in the
examples-scala-2 folder and are identical to Scala 3 where possible except for syntax.
Two major differences:
- Scala 3 allows us to write Union types
A | Band this is useful for scenarios of multiple return types across arbitrary lines. This is used heavily in the
CRUDStore.scalafile for Scala 3 but this code had to be converted to
Eitherin Scala 2.
- Scala 3 has
opaque typemodifiers for types that wrap existing types with no runtime overhead. Code using this style was converted to the much more verbose "wrapper class" style for Scala 2. You can see this in
This example shows a kind of DSL that is relatively simple to implement in as both an ADT as well as a "tagless final" style algebra. Both approaches allow for the same code to be written, but they are encoded in slightly different ways.
The ADT approach requires some kind of data structure to work, so we have a compiler for a
List[CalculationOp] that runs our sequence of operations.
The tagless approach, on the other hand, contains a given interpreter for the
State type in Cats.
To make this a little easier for end-users, an opaque type is used to hide the implementation details and allow us to write programs in this embedded language without much thought.
For examples, see the tests
This is a more involved example showing the way we can use an embedded DSL solution to model how we want our programs to compose together.
Inside, we have one main algebra,
CRUDStore, that acts as an interface for storing key/value pairs.
We also have two type classes:
Keyed- Describes data that has an extractable "key" value
StatusCodeMapping- Describes data that can map directly to an http4s
CRUDRequest- Boilerplate ADT for types of requests that could create/read/update/delete from
CRUDResponse- The counterpart of
CRUDRequestand the response type of any action that touches
And one opaque wrapper around
RequestHandler, that allows us to define functions with a type signature
Request => F[Response].
We also have some special syntax to convert a
RequestHandler with a
StatusCodeMapping for its response type into http4s
HttpRoutes to plug right into a web server, and a constructor method
RequestHandler.crudHandler that creates a
RequestHandler specially tailored to handle CRUD requests/responses.
An application that uses
CRUDLang to define a very basic CRUD server for movies.
Movie type as well as a simple
Init script that we write using the
CRUDStore algebra, plus
Applicative so we can sequence operations.
To talk to the server, you can use any REST client or use the
post.sh script in this repository along with any properly-formatted JSON as-needed.