1 Language-Oriented Programming
Goals |
— |
— |
1.1 Welcome to the 2019 Racket School of Programming Languages
1.1.1 Who are we? What are doing here?
For now, we just say “hello” and at the end of this first lecture, we’ll say what we’re doing here.
1.1.2 Who are you? Why are you here?
Please introduce yourself to the Racket team and your peers. In the past we have found that these introductions often intrigue others about your background and open connections. So in this spirit, please
tell us who you are, perhaps including a special tidbit about yourself
what you do for a living and how it related to Racket
why you chose to come to Racket week.
1.2 One Project, Many Programming Languages
It has become common that a software project employs many different programming languages. A “full stack” web application has software running in the web browser and the web server, and this software is rarely written in the same language. Furthermore the server is hardly ever a monolithic piece of software in one language. It typically glues together code that interprets requests (from the network), turns them into database queries, checks some business logic, and many more actions. Each of them might have been written in a different language (and possibly in a different era).
A few years ago a colleague from IBM presented (roughly) the following stack during his keynote address at POPL:
Programming with multiple external programming languages has been a reality for decades. It still is. Here are reasons why projects use many languages:
history—
someone started a project in a language, and the language falls out of favor. platform—
a new platform appears and demands attention. The new platform (terminal, pc, browser, mobile) does not support the language in which the software is currently written. expressiveness, productivity—
on rare occasions, a team of developers can convince the project manager that a new programming language will make them more productive than the one that has been used so far.
While one could call this form of programming, “language-oriented programming” this is a wider notion than the one we care about. What we do care about is the rationalization that different languages make solving different problems easier. And programming language designers have long ago recognized this fact, as a look at any programming language from the last 30 or 40 years shows.
1.3 One Programming Language, Many Languages
Almost every modern programming language comes with several distinct sub-languages that deal with distinct programming domains. Let’s look at a couple of simple ones in Racket.
"~a :: ~a\n"
; formatting strings to prepare for printing (printf "~a :: ~a\n" "hello" 'String)
(format "~a :: ~a\n" "hello" 'String)
; String -> False of [List String Char-String Char-String]) (define (extract-digits year) (regexp-match "20(.)(.)" year))
(extract-digits "2018") (extract-digits "1999")
; String -> False of [List String Digit-String Digit-String]) (define (extract-digits-version-2 year) (regexp-match #px"20(\\d)(\\d)" year))
; dealing with events from the environment (require 2htdp/universe) (require 2htdp/image) (define (main s0) (big-bang s0 [on-tick sub1] [stop-when zero?] [to-draw (lambda (s) (circle (+ 100 (* s 10)) 'solid 'red))]))
(define simple-tree '(a 1 2 3)) (match simple-tree [`(a ,(? number? x) ,y) (+ x y)] [`(a ,x ,y ,z) (* (+ x y) z)] [else "error"])
Of course there are other embedded languages that most programming languages have to support in this day and age, with database queries being an important one.
Think What kind of embedded domain-specific languages does your favorite programming language support?
Language designers accept that code communicates ideas (about problems and
solutions) across time and that clear expression of ideas greatly
facilitates communication. They therefore include these sub-languages
because they know that these niche problem areas in programming—
Composition is a mere syntactic act.
Computation is accomplished via translation into the host.
Communication is easy because embedded programs compute host values. Of course, this form of communicating poses its own problems.
But normally language designers do not enable software developers to create languages for niche application areas. Racketeers do, because they trust programmers.
1.4 One Racket Programmer, Many Languages
Racket empowers developers to add (sub)languages, and the process of adding these languages to the existing eco-system is free of any friction.
Racket supports a large spectrum of LOP in a reasonably friction-free and productive manner. The key is its API for the front-end of its implementation, that is, the syntax system, the ability to write compile-time functions, and the possibility to hook such functions into the compiler.
As a result, Racket is easy to extend. Adding new syntactic forms is just a matter of writing compile-time functions. You would write such functions because you want to abstract over recurring patterns in your code that cannot be abstracted over with functions (or other means of conventional abstraction).
|
|
|
Racket’s notion of language extension goes back to the primitive Lisp macros from 1964. Unsurprisingly, the idea has been thoroughly studied in the intervening 55 years, and Racketeers have advanced it more than any other language community.
One direction of advancement concerns the creation of language modules. Like all modern languages, Racket supports modules and a modular style of programming. Unlike in other languages, a Racket programmer chooses the programming language for each module in a software base independently of what languages the other components are written in. Conversely, a language is just a module. So to construct languages we write modules and to write modules we use languages. This notion of langauge-modules is key to writing software systems in Racket.
|
|
|
Where there are languages, people will ask for types. The Racket story of typed domain-specific languages is still in flux but we have one now. The Turnstile system allows programmers to write down the type system within the syntax extension system, and they get a typed language. But, this is where the Racket world is pushing the boundaries. Turnstile is a research prototype, and that’s why this week is a research summer school.
The final stage of LOP concerns the creation of embedded languages. This lecture demonstrated two languages embedded at the fine-grained level of expressions: dealing with events and matching algebraic patterns. These languages exist in all kinds of programming languages, but in all but one they have to be built into the compiler. In Racket, such languages are libraries.
Building languages that interleave with Racket expressions is possible but
our infrastructure remains somewhat primitive for this area. Like the above
language efforts, we want the creator of such embedded languages to inherit
as many “good things” from Racket as possible—
(define (private-adder x) (map add1 x)) (define-match-expander adder (lambda (stx) (syntax-parse stx [(_ x ...) #'(? (curry equal? (private-adder (list x ...))))])) (lambda (stx) (syntax-parse stx [(_ x ...) #'(private-adder (list x ...))])))
(adder 1 2 3)
Now we can explain what the following days, lectures and labs, will teach you.
1.5 Who are we? What are doing here?
Day 1 Matthias will review (for some participants, introduce) a simple model of Racket’s front-end implementation.
Jay will show how to use it to define language extensions.
Day 2 Jay will cover more advanced techniques using Racket’s syntax system, including issues of scope and phasing.
Day 3 Matthew will use the tools from the previous two days to build domain-specific languages.
Day 4 Jesse will show you how to equip domain-specific languages with type systems, in theory and practice.
Day 5 Robby will set up an extended lab that will give you a glimpse at fine-grained embedded languages.
We will wrap up the summer school with a presentation of a language gem by Robby and some concluding words by Matthias.