Revision as of 19:54, 18 August 2011 editElibarzilay (talk | contribs)185 edits I'm an expert on the subject, no need for that request now.← Previous edit | Latest revision as of 23:58, 7 January 2024 edit undoJerryobject (talk | contribs)Extended confirmed users15,399 editsm Cut needless carriage return whitespace characters in sections: to standardize, aid work via small screens. | ||
(76 intermediate revisions by 46 users not shown) | |||
Line 1: | Line 1: | ||
{{Main article|Racket (programming language)}} | |||
<!-- Please do not remove or change this AfD message until the issue is settled --> | |||
Racket has been under active development as a vehicle for ] since the mid-1990s, and has accumulated many features over the years. This article describes and demonstrates some of these features. Note that one of Racket's main design goals is to accommodate creating new ]s, both ]s and completely new languages.<ref name="languages-as-libraries">{{cite conference | |||
{{Article for deletion/dated|page=Racket features|timestamp=20110816124929|year=2011|month=August|day=16|substed=yes|help=off}} | |||
|last1=Tobin-Hochstadt |first1=S. | |||
<!-- For administrator use only: {{Old AfD multi|page=Racket features|date=16 August 2011|result='''keep'''}} --> | |||
|last2=St-Amour |first2=V. | |||
<!-- End of AfD message, feel free to edit beyond this point --> | |||
|last3=Culpepper |first3=R. | |||
|last4=Flatt |first4=M. | |||
|last5=Felleisen |first5=M. | |||
|year=2011 | |||
|title=Languages as Libraries | |||
|book-title=Programming Language Design and Implementation | |||
|url=http://www.ccs.neu.edu/scheme/pubs/pldi11-thacff.pdf}} | |||
</ref> | |||
Therefore, some of the following examples are in different languages, but they are all implemented in Racket. Please refer to ] for more information. | |||
The core Racket implementation is highly flexible. Even without using dialects, it can function as a full-featured scripting language, capable of running both with and without windows-native ] (GUI), and capable of tasks from web server creation to graphics. | |||
{{main|Racket (programming language)}} | |||
This article describes the features of the ] programming language, and lists some examples for these features and others. Since Racket's greatest strength is in making it easy to define and use language dialects, DSL, and completely new languages, this page also lists and describes some of these languages. Please refer to the main article for more information. | |||
The examples give an overall perspective on how ] can be used in different application domains. Most of them come from . To run them, install Racket, start ], and paste the example program into the top area in DrRacket, and click the Run button. Alternatively, save the program to a file and run <code>racket</code> on the file. | |||
== Runtime Support == | |||
=== Garbage Collection, Tail Calls, and Space Safety === | |||
Racket can use three different ]: | |||
* Originally, the conservative ] has been used. However, conservative collection is impractical for long-running processes such as the web browser—such processes tend to slowly leak memory. In addition, there are pathological cases where a conservative collector leaks memory fast enough to make certain programs impossible to run. For example, when traversing an infinite list, a single conservative mistake of retaining a pointer leads to keeping the complete list in memory, quickly overflowing available memory. This collector is often referred to "CGC" in the Racket community. | |||
== Runtime support == | |||
=== Garbage collection, tail calls, space safety === | |||
Racket can use three different ]: | |||
* Originally, the conservative ] was used. However, conservative collection is impractical for long-running processes such as a web server—such processes tend to slowly leak memory. Also, there are pathological cases where a conservative collector leaks memory fast enough to make certain programs impossible to run. For example, when traversing an infinite list, a single conservative mistake of retaining a pointer leads to keeping the complete list in memory, quickly overflowing available memory. This collector is often referred to as "CGC" in the Racket community. | |||
* SenoraGC is an alternative conservative garbage collector that is intended mainly for debugging and memory tracing. | * SenoraGC is an alternative conservative garbage collector that is intended mainly for debugging and memory tracing. | ||
* The moving memory manager (aka "3m") is a precise garbage collector, and it has been Racket's default collector since 2007. This collector is a generational one, and it supports memory accounting via custodians (see below). The collector is implemented as a C source transformer that is itself written in Racket. Therefore, the build process uses the conservative collector for ]. | |||
Like all implementations in the ] family, Racket implements full ] elimination. Racket takes this further: the language is made fully safe-for-space, via ]. This complements the precise garbage collector and in some cases, like in the implementation of Lazy Racket, the two features are crucial for proper execution. This is in addition to further compiler optimizations such as ] and ]. | |||
* The moving memory manager (aka "3m") is a precise garbage collector, and it has been Racket's default collector since 2007. This collector is a generational one, and it supports memory accounting via custodians (see below). The collector is implemented as a C source transformer that is itself written in Racket. The build process is therefore using the conservative collector for bootstrapping. | |||
Like all implementations in the ] family, Racket implements full ]. Racket takes this further: the language is made fully safe-for-space, via ]. This complements the precise garbage collector, and in some cases like in the implementation of Lazy Racket, the two features are crucial for proper execution. This is in addition to additional compiler optimizations such as ] and to its ]. | |||
=== System Interface and Scripting === | |||
=== System interface and scripting === | |||
Racket's system interface includes asynchronous ], green threads, synchronization channels, semaphores, ], and ] sockets. | |||
Racket's system interface includes asynchronous ], ]s, synchronization channels, semaphores, ], and ] (TCP) sockets. | |||
The following program starts an "echo server" on port 12345. | The following program starts an "echo server" on port 12345. | ||
< |
<syntaxhighlight lang="racket"> | ||
#lang racket | #lang racket | ||
Line 38: | Line 38: | ||
;; handle an incoming connection in a (green) thread | ;; handle an incoming connection in a (green) thread | ||
(thread (λ () (copy-port in out) (close-output-port out))) | (thread (λ () (copy-port in out) (close-output-port out))) | ||
;; and immediately loop back to accept |
;; and immediately loop back to accept more clients | ||
(echo-server)) | (echo-server)) | ||
</syntaxhighlight> | |||
</source> | |||
The combination of dynamic compilation and a rich system interface makes Racket a capable scripting language, similar to ] or ]. | The combination of dynamic compilation and a rich system interface makes Racket a capable scripting language, similar to ] or ]. | ||
The following example demonstrates walking a directory tree, starting at the current directory. |
The following example demonstrates walking a directory tree, starting at the current directory. It uses the <code>in-directory</code> function to construct a sequence that walks the tree. The <code>for</code> form binds <code>path</code> to each path in the sequence, and <code>regexp-match?</code> tests these paths against the given ] pattern. | ||
< |
<syntaxhighlight lang="racket"> | ||
#lang racket | #lang racket | ||
;; Finds Racket sources in all subdirs | ;; Finds Racket sources in all subdirs | ||
Line 53: | Line 53: | ||
(when (regexp-match? #rx"rkt$" path) | (when (regexp-match? #rx"rkt$" path) | ||
(printf "source file: ~a\n" path))) | (printf "source file: ~a\n" path))) | ||
</syntaxhighlight> | |||
</source> | |||
The next example uses a hash table to record previously seen lines and print only unique ones. | The next example uses a hash table to record previously seen lines and print only unique ones. | ||
< |
<syntaxhighlight lang="racket"> | ||
#lang racket | #lang racket | ||
;; Report each unique line from stdin | ;; Report each unique line from stdin | ||
Line 65: | Line 65: | ||
(unless (hash-ref saw line #f) | (unless (hash-ref saw line #f) | ||
(displayln line)) | (displayln line)) | ||
(hash-set! saw line #t))) |
(hash-set! saw line #t))) | ||
</syntaxhighlight> | |||
</source> | |||
Both of these programs can be run in ], or on the command line, via the <code>racket</code> executable. |
Both of these programs can be run in ], or on the command line, via the <code>racket</code> executable. Racket ignores an initial ] line, making it possible to turn such programs to executable scripts. The following script demonstrates this, in addition to using Racket's library for ]: | ||
< |
<syntaxhighlight lang="racket"> | ||
#!/usr/bin/env racket | #!/usr/bin/env racket | ||
#lang racket | #lang racket | ||
Line 79: | Line 79: | ||
) | ) | ||
(when (regexp-match? (pregexp re) line) | (when (regexp-match? (pregexp re) line) | ||
(printf "~a:~a: ~a~n" p num line)))) | (printf "~a:~a: ~a~n" p (+ num 1) line)))) | ||
</syntaxhighlight> | |||
</source> | |||
The script is a grep-like utility, expecting three command-line arguments: a base directory, a ], and a (perl-compatible) regular expression. |
The script is a grep-like utility, expecting three command-line arguments: a base directory, a ], and a (perl-compatible) regular expression. It scans the base directory for files with the given suffix, and print lines matching the regexp pattern. | ||
=== Resource management and sandboxing === | |||
== Web and Network Programming == | |||
Racket features the concept of a "custodian": a kind of value that acts as a resource manager. This is often used in network servers, where each connection is dealt with in a new custodian, making it easy to "clean-up" all resources that might have been left open by the handler (e.g., open ports). The following extends the "echo server" example with such a custodian use: | |||
<syntaxhighlight lang="racket"> | |||
#lang racket | |||
(define listener (tcp-listen 12345)) | |||
;; per-connection handler | |||
(define (handler in out) | |||
(copy-port in out) | |||
(close-output-port out)) | |||
(let echo-server () | |||
(define-values (in out) (tcp-accept listener)) | |||
(thread (λ () (let () | |||
(parameterize () | |||
(handler in out) | |||
(custodian-shutdown-all c))))) | |||
(echo-server)) | |||
</syntaxhighlight> | |||
Custodians, combined with the memory accounting feature of the 3m garbage collector, and several added runtime parameters that control more aspects of the runtime, make it possible to create fully safe sandboxed execution contexts. The <code>racket/sandbox</code> library provides this kind of functionality in a simple way. The following example creates a ''] (REPL) server'' on the specified port; connecting to this port will look like a plain Racket REPL, except that the evaluation is subject to the various protection aspects of the sandbox. For example, it is not possible to access the ] from this REPL, create network connection, run subprocesses, or use too much time or memory. (In fact, this REPL is safe enough to be given out publicly.) | |||
<syntaxhighlight lang="racket"> | |||
#lang racket | |||
(require racket/sandbox) | |||
(define e (make-evaluator 'racket/base)) | |||
(let-values () | |||
(parameterize ( | |||
) | |||
(read-eval-print-loop) | |||
(fprintf o "\nBye...\n") | |||
(close-output-port o))) | |||
</syntaxhighlight> | |||
== Web and network programming == | |||
The next example implements a ] using the <code>web-server/insta</code> language. Each time a connection is made to the server, the <code>start</code> function is called to get the ] to send back to the client. | |||
The next example implements a ] using the <code>web-server/insta</code> language. Each time a connection is made to the server, the <code>start</code> function is called to get the ] to send back to the client. | |||
< |
<syntaxhighlight lang="racket"> | ||
#lang web-server/insta | #lang web-server/insta | ||
;; A tiny "hello world" web server | ;; A tiny "hello world" web server | ||
Line 93: | Line 130: | ||
(define (start request) | (define (start request) | ||
(response/xexpr '(html (body "Hello World")))) | (response/xexpr '(html (body "Hello World")))) | ||
</syntaxhighlight> | |||
</source> | |||
Racket also includes the functions |
Racket also includes the functions needed to write scrapers and robots. As an example, the following function lists the Google results for a search string. | ||
< |
<syntaxhighlight lang="racket"> | ||
#lang racket | #lang racket | ||
;; Simple web scraper | ;; Simple web scraper | ||
Line 103: | Line 140: | ||
(require net/url net/uri-codec) | (require net/url net/uri-codec) | ||
(define (let-me-google-that |
(define (let-me-google-that str) | ||
(let* ( | (let* ( | ||
) | ) | ||
(regexp-match* rx (get-pure-port (string->url u))))) |
(regexp-match* rx (get-pure-port (string->url u))))) | ||
</syntaxhighlight> | |||
</source> | |||
The library also includes support for protocols other than http: | The library also includes support for protocols other than http: | ||
< |
<syntaxhighlight lang="racket"> | ||
#lang racket | #lang racket | ||
;; Sending a timed email alert from racket | ;; Sending a timed email alert from racket | ||
Line 123: | Line 160: | ||
(getenv "EMAIL") "Parking meter alert!" | (getenv "EMAIL") "Parking meter alert!" | ||
(list (getenv "EMAIL")) null null | (list (getenv "EMAIL")) null null | ||
'("Time to go out and move |
'("Time to go out and move the car.")) | ||
</syntaxhighlight> | |||
</source> | |||
== Graphics == | == Graphics == | ||
Graphic capabilities come in several different flavors that are intended for different audiences. The <code>2htdp/image</code> library provides convenient functions for constructing images. This library is mainly used by students in ] (HtDP) based courses. In the following example, a <code>sierpinski</code> function is defined and called (at the same time) to generate a ] of depth 8. | |||
<syntaxhighlight lang="racket"> | |||
Graphic capabilities come in several different flavors that are intended for different audiences. The <code>2htdp/image</code> library provides easy-to-use functions for constructing images, and DrRacket can display an image result just as it can display a number result. This library is mainly used by students in ]-based courses. In this case, a <code>sierpinski</code> function is defined and called (at the same time) to generate a ] of depth 8. | |||
<source lang="Scheme"> | |||
#lang racket | #lang racket | ||
;; A picture | ;; A picture | ||
Line 141: | Line 177: | ||
(let () | (let () | ||
(freeze (above t (beside t t)))))) | (freeze (above t (beside t t)))))) | ||
</syntaxhighlight> | |||
</source> | |||
DrRacket editors can contain images, and DrRacket displays image values just like any other type of value (such as integers or lists). Running the above program, for example, actually displays a Sierpinski triangle, which can be cut and pasted into another program. | |||
The <code>plot</code> library constructs image values for more mature audiences and needs. For example, the following program plots the sum of two <math>\mathbb{R} \times \mathbb{R} \times \mathbb{R} \rightarrow \mathbb{R}</math> (three-dimensional) Gaussians, as concentric, partially transparent surfaces: | |||
The next program uses the <code>plot</code> library to draw plots of functions. Note that plots are actual value, which DrRacket shows in graphical form. | |||
< |
<syntaxhighlight lang="racket"> | ||
#lang racket | #lang racket | ||
;; Visualize a sum of two 3D Gaussians as concentric isosurfaces | |||
;; draw a graph of cos and deriv^3(cos) | |||
;; Note: this example requires Racket 5.2 or later | |||
(require plot) | (require plot) | ||
;; Returns an R x R x R -> R Gaussian function centered at (cx,cy,cz) | |||
;; a curried derivative function | |||
(define (( |
(define ((gaussian cx cy cz) x y z) | ||
( |
(exp (- (+ (sqr (- x cx)) (sqr (- y cy)) (sqr (- z cz)))))) | ||
;; Lifts + to operate on three-argument functions | |||
(define (thrice f) (lambda (x) (f (f (f x))))) | |||
(define ((f3+ g h) x y z) (+ (g x y z) (h x y z))) | |||
;; Constructs an image value representing the sum of two Gaussians | |||
(plot (mix (line ((thrice deriv) sin) #:color 'red) | |||
(plot3d (isosurfaces3d (f3+ (gaussian 0 0 0) (gaussian 1.5 -1.5 0)) | |||
(line cos #:color 'blue)))} | |||
-1 2.5 -2.5 1 -1 1 | |||
</source> | |||
#:label "g")) ; labeling adds a legend | |||
</syntaxhighlight> | |||
Here, the <code>isosurfaces3d</code> function requires a three-argument function for its first argument, which the curried <code>f3+</code> supplies. Besides constructing image values, <code>plot</code> can also write files in Portable Network Graphics (]), Portable Document Format (]), ] and Scalable Vector Graphics (]) formats. | |||
=== GUI Programming === | |||
=== GUI programming === | |||
Racket implements a portable ] layer which the libraries mentioned above build on. It is implemented via the native ] API, via ] on ], and via ] on Linux and others. The Racket API is a class-based toolkit, somewhat related to ] which was used originally. | |||
Racket implements a portable ] layer which the libraries mentioned above build on. It is implemented via the native ] application programming interface (]), via ] on ], and via ]+ on ] and others. The Racket API is a class-based toolkit, somewhat related to ] which was used originally. | |||
The following simple guessing game demonstrates coding with the GUI toolkit. |
The following simple guessing game demonstrates coding with the GUI toolkit. The <code>frame%</code> class implements a top-level window, and <code>button%</code> implements a button. The <code>check</code> function defined here produces a function that is used for the button's callback action. | ||
< |
<syntaxhighlight lang="racket"> | ||
#lang racket/gui | #lang racket/gui | ||
;; A GUI guessing game | ;; A GUI guessing game | ||
Line 188: | Line 231: | ||
(send f show #t) ; show the window to start the application | (send f show #t) ; show the window to start the application | ||
</syntaxhighlight> | |||
</source> | |||
The GUI can be hand-coded in this way or with the help of a |
The GUI can be hand-coded in this way or with the help of a GUI designer program available on PLaneT.<ref name="PLaneT">: Racket's centralized package distribution system</ref> | ||
=== Slideshow === | |||
== Foreign Function Interface == | |||
]-based ]s can also be developed in Racket using the <code>slideshow</code> language, much like ], but with Racket's programming facilities. Elements of the slides are pictures that can be combined. | |||
For example, the following program displays in full-screen a title slide, followed by a slide with some pictures. The <code>vc-append</code> and <code>hc-append</code> functions combine pictures vertically and horizontally, respectively, and centered on the other axis. | |||
Racket features a ] that is based on ]. The interface allows writing unsafe low-level ]-like code, that can allocate memory, dereference pointers, call out to functions in ], and send out callbacks to Racket functions (using libffi closures). The core implementation is a thin layer atop libffi (written in C), and the full interface is then implemented via Racket code. The interface uses macros extensively, resulting in a convenient Racket-based ]. The language has a number of convenient features, such as uniform representation for higher-order functions (avoiding the pitfalls when callbacks and callouts are different), struct definitions that are similar to plain Racket structs, and custom function types that can represent input and output pointers, implicit arguments (e.g., an argument that provides the number of elements in a vector that is passed as another argument). | |||
<syntaxhighlight lang="racket"> | |||
#lang slideshow | |||
(slide | |||
The FFI can be used in a number of different ways: from writing a complete glue layer for a library (as done for Racket's ] binding), to quickly pulling out a single foreign function. An example of the latter approach: | |||
(text "Slideshow" 'roman 56) | |||
<source lang="Scheme"> | |||
(text "Making presentations in Racket" | |||
#lang scheme/base | |||
'roman 40)) | |||
(slide | |||
#:title "Some pictures" | |||
(apply vc-append | |||
(for/list () | |||
(define (scale+color p c) | |||
(colorize (scale p (/ (add1 i) 5)) c)) | |||
(hc-append | |||
(scale+color (filled-rectangle 100 50) "darkblue") | |||
(scale+color (disk 100) "darkgreen") | |||
(scale+color (arrow 100 (/ pi 6)) "darkred") | |||
)))) | |||
</syntaxhighlight> | |||
Extension packages also exist on PLaneT,<ref name="PLaneT"/> for example to include ] elements. | |||
== Foreign function interface == | |||
Racket features a ] that is based on ]. The interface allows writing unsafe low-level ]-like code, that can allocate memory, dereference pointers, call out to functions in ], and send out callbacks to Racket functions (using libffi closures). The core implementation is a thin layer atop libffi (written in C), and the full interface is then implemented via Racket code. The interface uses macros extensively, resulting in an expressive Racket-based ]. This language has a number of useful features, such as uniform representation for higher-order functions (avoiding the pitfalls when callbacks and callouts are different), struct definitions that are similar to plain Racket structs, and custom function types that can represent input and output pointers, implicit arguments (e.g., an argument that provides the number of elements in a vector that is passed as another argument). By using this interface to access underlying GUI toolkits, Racket implements its own GUI layer, in Racket.<ref name="gui-rebuild">{{cite web |date=2010-12-08 |url=http://blog.racket-lang.org/2010/12/racket-version-5.html |title=Rebuilding Racket's Graphics Layer |url-status=dead |archive-url=https://web.archive.org/web/20130202224029/http://blog.racket-lang.org/2010/12/racket-version-5.html |archive-date=2013-02-02 |access-date=2013-07-07}}</ref> | |||
The FFI can be used in a number of different ways: from writing a complete glue layer for a library (as done for Racket's ] binding), to quickly pulling out a single foreign function. An example of the latter approach: | |||
<syntaxhighlight lang="racket"> | |||
#lang racket/base | |||
;; Simple use of the FFI | ;; Simple use of the FFI | ||
Line 208: | Line 276: | ||
-> ))) | -> ))) | ||
(mci-send-string "play sound.wav wait") | (mci-send-string "play sound.wav wait") | ||
</syntaxhighlight> | |||
</source> | |||
== Language |
== Language extensions == | ||
Racket's most notable feature is its ability to build new ] and ] languages. This is the result of combining a number of important features: | |||
Racket's most notable feature is its ability to build new ] and ] languages. This is the result of combining a number of important features: | |||
* a flexible module system that is used for linking code and for namespace management, | * a flexible module system that is used for linking code and for namespace management, | ||
* an extensive macro |
* an extensive macro system—functioning as a compiler-API—that can create new syntactic forms, | ||
* a rich runtime system, providing features that language implementors can use, like (composable, delimited) continuations, resource management, etc, | * a rich runtime system, providing features that language implementors can use, like (composable, delimited) continuations, resource management, etc., | ||
* a way to specify (and implement) parsers for new language syntaxes. | * a way to specify (and implement) parsers for new language syntaxes. | ||
The module system plays an important role in combining these features, and making it possible to write code that spans across a number of modules, where each can be written in a different language. | The module system plays an important role in combining these features, and making it possible to write code that spans across a number of modules, where each can be written in a different language. | ||
Such languages are used extensively in the Racket distribution and in user libraries. |
Such languages are used extensively in the Racket distribution and in user libraries. In fact, creating a new language is so straightforward, that there are some languages that have less than a handful of uses. | ||
Racket comes with a number of useful languages, some are very different from Racket's default language. | Racket comes with a number of useful languages, some are very different from Racket's default language. | ||
=== Scribble === | === Scribble === | ||
Scribble, Racket's documentation system, comes in the form of a number of languages that are used to write prose. It is used for Racket's documentation, as well as writing books and articles. Actually, rather than a single "scribble" language, it is a family of (very similar) dialects, each for a different purpose. | |||
To run the following example, copy it into DrRacket and click one of the two scribble rendering buttons that will appear (PDF rendering requires ]). Alternatively, use the <code>scribble</code> executable on the file. | |||
Scribble, Racket's documentation system, comes in the form of a number of languages that are used to write prose. It is used for Racket's extensive , as well as writing books and articles. Actually, rather than a single "scribble" language, it is a family of (very similar) dialects, each for a different purpose. | |||
<syntaxhighlight lang="moin"> | |||
To run the following example, copy it into DrRacket and click one of the two scribble rendering buttons that will appear (PDF rendering requires ]). Alternatively, use the <code>scribble</code> executable on the file. | |||
<source lang="Scheme"> | |||
#lang scribble/base | #lang scribble/base | ||
@; Generate a PDF or an HTML document using `scribble' | @; Generate a PDF or an HTML document using `scribble' | ||
Line 246: | Line 313: | ||
Take one down, pass it around, | Take one down, pass it around, | ||
@N-- bottles of beer on the wall.})) | @N-- bottles of beer on the wall.})) | ||
</syntaxhighlight> | |||
</source> | |||
The most striking feature of the Scribble languages is their use of a new syntax, which is designed specifically for textually |
The most striking feature of the Scribble languages is their use of a new syntax, which is designed specifically for textually rich code.<ref>{{cite conference |last1=Barzilay |first1=E. |title=The Scribble Reader |book-title=Scheme and Functional Programming |year=2009 |url=http://www.ccs.neu.edu/racket/pubs/scheme2009-b.pdf}}</ref> The syntax allows free-form text, string interpolation, customizable quotations, and is useful in other applications such as ], generating text, and HTML template systems. Note that the syntax extends plain S-expressions, and is implemented as an alternative input for such expressions. | ||
< |
<syntaxhighlight lang="moin"> | ||
#lang scribble/text | #lang scribble/text | ||
Hi, | Hi, | ||
Line 256: | Line 323: | ||
@thrice{SPAM}! | @thrice{SPAM}! | ||
@thrice{HAM}! | @thrice{HAM}! | ||
</syntaxhighlight> | |||
</source> | |||
=== Typed Racket === | === Typed Racket === | ||
Typed Racket is a ] variant of Racket. The ] that it implements is unique in that the motivation in developing it was accommodating as much idiomatic Racket code as possible—as a result, it includes subtypes, unions, and much more.<ref>{{cite conference |last1=Tobin-Hochstadt |first1=S. |last2=Felleisen |first2=M. |year=2008 |title=The Design and Implementation of Typed Scheme |book-title=Principles of Programming Languages}}</ref> Another goal of Typed Racket is to allow migration of parts of a program into the typed language, so it accommodates calling typed code from untyped code and vice versa, generating dynamic ] to enforce type invariants.<ref>{{cite conference |last1=Tobin-Hochstadt |first1=S. |last2=Felleisen |first2=M. |year=2006 |title=Interlanguage Migration: From Scripts to Programs |book-title=Dynamic Languages Symposium}}</ref> This is considered a desirable feature of an application's lifetime stages, as it matures from "a script" to "an application", where static typing helps in maintenance of a large body of code. | |||
<syntaxhighlight lang="racket"> | |||
Typed Racket is a ] variant of Racket. The ] that it implements is unique in that the motivation in developing it was accommodating as much idiomatic Racket code as possible—as a result, it includes subtypes, unions, and much more. Another goal of Typed Racket is to allow migration of parts of a program into the typed language, so it accommodates calling typed code from untyped code and vice versa, generating dynamic ] to enforce type invariants. This is considered a desirable feature of an application's lifetime stages, as it matures from "a script" to "an application", where static typing helps in maintenance of a large body of code. | |||
<source lang="Scheme"> | |||
#lang typed/racket | #lang typed/racket | ||
Line 273: | Line 339: | ||
(tog (list 5 "hello " 1/2 "world" (sqrt -1))) | (tog (list 5 "hello " 1/2 "world" (sqrt -1))) | ||
</syntaxhighlight> | |||
</source> | |||
=== Lazy Racket === | === Lazy Racket === | ||
The <code>lazy</code> language is a language with ] semantics, similar to ]. In the following example, <code>fibs</code> is an infinite list which 1000th element will not be computed until its value is needed for the printout. | |||
<syntaxhighlight lang="Racket"> | |||
The <code>lazy</code> language is a language with ] semantics, similar to ]. In the following example, <code>fibs</code> is an infinite list whose 1000th element will not be computed until its value is needed for the printout. | |||
<source lang="Scheme"> | |||
#lang lazy | #lang lazy | ||
;; An infinite list: | ;; An infinite list: | ||
Line 286: | Line 351: | ||
;; Print the 1000th Fibonacci number: | ;; Print the 1000th Fibonacci number: | ||
(print (list-ref fibs 1000)) | (print (list-ref fibs 1000)) | ||
</syntaxhighlight> | |||
</source> | |||
=== Logic |
=== Logic programming === | ||
Racket comes with three ] languages: Racklog, a ]-like language; a ] implementation; and a ] port. Unlike the Scribble syntax, the first two of these languages use an all-new syntax rather than an extension of S-expressions. If used it in DrRacket, it provides proper highlighting, the usual host of tools check syntax, and a Prolog/Datalog REPL. | |||
<syntaxhighlight lang="prolog"> | |||
Racket comes with two ] languages: Racklog, a ]-like language, and a ] implementation. Unlike the Scribble syntax, these languages use a completely new syntax rather than an extension of S-expressions. If you use it in DrRacket, you'll see that it provides proper highlighting, the usual host of tools check syntax, and a Prolog/Datalog REPL. | |||
<source lang="Prolog"> | |||
#lang datalog | #lang datalog | ||
Line 301: | Line 365: | ||
ancestor(A, B)? | ancestor(A, B)? | ||
</syntaxhighlight> | |||
</source> | |||
=== |
=== Education tools === | ||
The PLT group which develops Racket has traditionally been involved in education at all levels. One of the earliest research ideas that the group promoted is the use of language levels, which restrict new students while providing them with helpful error messages that fit the student's level of knowledge. This approach is heavily used in ] (HtDP), the textbook that several PLT developers have authored, and in the ] project. The following program uses the <code>htdp/bsl</code>—the "beginning student language". It uses the <code>2htdp/image</code> library for creating pictures in the teaching languages, and the <code>2htdp/universe</code> library for interactive animations. | |||
<syntaxhighlight lang="racket"> | |||
The PLT group which develops Racket has traditionally been involved in education at all levels. One of the earliest research ideas that the group promoted is the use of language levels, which restrict new students while providing them with helpful error messages that fit the student's level of knowledge. This approach is heavily used in ], the textbook that several PLT developers have authored, as well as in the ] project. The following program uses the <code>htdp/bsl</code>—the "beginning student language". It uses the <code>2htdp/image</code> library for creating pictures in the teaching languages, and the <code>2htdp/universe</code> library for interactive animations. | |||
<source lang="Scheme"> | |||
#lang htdp/bsl | #lang htdp/bsl | ||
;; Any key inflates the balloon | ;; Any key inflates the balloon | ||
Line 322: | Line 385: | ||
(big-bang 50 (on-key blow-up) (on-tick deflate) | (big-bang 50 (on-key blow-up) (on-tick deflate) | ||
(to-draw balloon 200 200)) | (to-draw balloon 200 200)) | ||
</syntaxhighlight> | |||
</source> | |||
=== Algol === | |||
=== ALGOL === | |||
Racket comes with a complete implementation of the ] language. This language is, however, not implemented via <code>#lang</code> yet. Instead, it must be used inside DrRacket after choosing the "Algol 60" language from the language selection dialog. | |||
Racket comes with a full implementation of the ] language. | |||
<source lang="Algol68"> | |||
<syntaxhighlight lang="pascal"> | |||
#lang algol60 | |||
begin | begin | ||
integer procedure SIGMA(x, i, n); | integer procedure SIGMA(x, i, n); | ||
Line 342: | Line 405: | ||
printnln(SIGMA(q*2-1, q, 7)); | printnln(SIGMA(q*2-1, q, 7)); | ||
end | end | ||
</syntaxhighlight> | |||
</source> | |||
===Plai and plai-typed=== | |||
=== Additional Languages === | |||
<syntaxhighlight lang="Racket"> #lang plai </syntaxhighlight> | |||
<syntaxhighlight lang="Racket"> #lang plai-typed </syntaxhighlight> | |||
Another supported language is plai which like racket can be typed or untyped. "Modules written in plai export every definition (unlike scheme)."<ref>{{Cite web |url=http://docs.racket-lang.org/plai/plai-scheme.html?q=plai |title=1 PLAI Scheme}}</ref> "The Typed PLAI language differs from traditional Racket most importantly by being statically typed. It also gives some useful new constructs: define-type, type-case, and test."<ref>Krishnamurthi, Shriram. "Programming Languages: Application and Interpretation." Programming Languages: Application and Interpretation. Brown University, n.d. Web. 14 Mar. 2016. <http://cs.brown.edu/courses/cs173/2012/book/>.</ref> | |||
=== Creating languages === | |||
Finally, the following example is an *implementation* of a new language: | |||
Finally, the following example is an '''implementation''' of a new language: | |||
<source lang="Scheme"> | |||
<syntaxhighlight lang="racket"> | |||
#lang racket | #lang racket | ||
(provide (except-out (all-from-out racket) | (provide (except-out (all-from-out racket) | ||
Line 355: | Line 422: | ||
(define-syntax-rule (app f . xs) | (define-syntax-rule (app f . xs) | ||
(if (hash? f) (hash-ref f . xs) (f . xs))) | (if (hash? f) (hash-ref f . xs) (f . xs))) | ||
</syntaxhighlight> | |||
</source> | |||
This language: | This language: | ||
Line 361: | Line 428: | ||
* except for two special "hook macros" that implement unbound variable lookup and function calls, instead of these, new forms are provided to | * except for two special "hook macros" that implement unbound variable lookup and function calls, instead of these, new forms are provided to | ||
** implicitly quote all unknown variables | ** implicitly quote all unknown variables | ||
** allow hash tables to be used as functions, where the arguments are used for hash-table lookup.<ref>Note that <code>#%app</code> is a macro that is used in all function calls, making this language not too efficient, as every function call incurs an |
** allow hash tables to be used as functions, where the arguments are used for hash-table lookup.<ref>Note that <code>#%app</code> is a macro that is used in all function calls, making this language not too efficient, as every function call incurs an added condition. Also, the macro evaluates the function expression twice, so it should not be taken as an example of good macro-programming.</ref> | ||
If this code is stored in a <code>mylang.rkt</code> file, |
If this code is stored in a <code>mylang.rkt</code> file, it can be used as follows: | ||
< |
<syntaxhighlight lang="racket"> | ||
#lang s-exp "mylang.rkt" ; sexpr syntax, using mylang semantics | #lang s-exp "mylang.rkt" ; sexpr syntax, using mylang semantics | ||
(define h (make-hasheq)) | (define h (make-hasheq)) | ||
(hash-set! h A B) ; A and B are self-evaluating here | (hash-set! h A B) ; A and B are self-evaluating here | ||
(h A) ; the hash table is used as a function | (h A) ; the hash table is used as a function | ||
</syntaxhighlight> | |||
</source> | |||
== References |
== References == | ||
{{Reflist}} | {{Reflist}} | ||
* {{CCBYSASource|sourcepath=http://racket-lang.org/|sourcearticle=Racket|revision=445553008}} | |||
==External links== | |||
* {{Official website|racket-lang.org}} | |||
* | |||
{{Lisp programming language}} | |||
] | ] | ||
] | |||
] |
Latest revision as of 23:58, 7 January 2024
Main article: Racket (programming language)Racket has been under active development as a vehicle for programming language research since the mid-1990s, and has accumulated many features over the years. This article describes and demonstrates some of these features. Note that one of Racket's main design goals is to accommodate creating new programming languages, both domain-specific languages and completely new languages. Therefore, some of the following examples are in different languages, but they are all implemented in Racket. Please refer to the main article for more information.
The core Racket implementation is highly flexible. Even without using dialects, it can function as a full-featured scripting language, capable of running both with and without windows-native graphical user interface (GUI), and capable of tasks from web server creation to graphics.
Runtime support
Garbage collection, tail calls, space safety
Racket can use three different garbage collectors:
- Originally, the conservative Boehm garbage collector was used. However, conservative collection is impractical for long-running processes such as a web server—such processes tend to slowly leak memory. Also, there are pathological cases where a conservative collector leaks memory fast enough to make certain programs impossible to run. For example, when traversing an infinite list, a single conservative mistake of retaining a pointer leads to keeping the complete list in memory, quickly overflowing available memory. This collector is often referred to as "CGC" in the Racket community.
- SenoraGC is an alternative conservative garbage collector that is intended mainly for debugging and memory tracing.
- The moving memory manager (aka "3m") is a precise garbage collector, and it has been Racket's default collector since 2007. This collector is a generational one, and it supports memory accounting via custodians (see below). The collector is implemented as a C source transformer that is itself written in Racket. Therefore, the build process uses the conservative collector for bootstrapping.
Like all implementations in the Scheme family, Racket implements full tail call elimination. Racket takes this further: the language is made fully safe-for-space, via live variable analysis. This complements the precise garbage collector and in some cases, like in the implementation of Lazy Racket, the two features are crucial for proper execution. This is in addition to further compiler optimizations such as lambda lifting and just-in-time compilation.
System interface and scripting
Racket's system interface includes asynchronous non-blocking I/O, green threads, synchronization channels, semaphores, sub-processes, and Transmission Control Protocol (TCP) sockets.
The following program starts an "echo server" on port 12345.
#lang racket (define listener (tcp-listen 12345)) (let echo-server () ;; create a TCP server (define-values (in out) (tcp-accept listener)) ;; handle an incoming connection in a (green) thread (thread (λ () (copy-port in out) (close-output-port out))) ;; and immediately loop back to accept more clients (echo-server))
The combination of dynamic compilation and a rich system interface makes Racket a capable scripting language, similar to Perl or Python.
The following example demonstrates walking a directory tree, starting at the current directory. It uses the in-directory
function to construct a sequence that walks the tree. The for
form binds path
to each path in the sequence, and regexp-match?
tests these paths against the given regexp pattern.
#lang racket ;; Finds Racket sources in all subdirs (for () ; iterate over the current tree (when (regexp-match? #rx"rkt$" path) (printf "source file: ~a\n" path)))
The next example uses a hash table to record previously seen lines and print only unique ones.
#lang racket ;; Report each unique line from stdin (let () (for () (unless (hash-ref saw line #f) (displayln line)) (hash-set! saw line #t)))
Both of these programs can be run in DrRacket, or on the command line, via the racket
executable. Racket ignores an initial shebang line, making it possible to turn such programs to executable scripts. The following script demonstrates this, in addition to using Racket's library for command-line argument parsing:
#!/usr/bin/env racket #lang racket (command-line #:args (base-dir ext re) (for ( #:when (regexp-match? (string-append "" ext "$") p) ) (when (regexp-match? (pregexp re) line) (printf "~a:~a: ~a~n" p (+ num 1) line))))
The script is a grep-like utility, expecting three command-line arguments: a base directory, a filename extension, and a (perl-compatible) regular expression. It scans the base directory for files with the given suffix, and print lines matching the regexp pattern.
Resource management and sandboxing
Racket features the concept of a "custodian": a kind of value that acts as a resource manager. This is often used in network servers, where each connection is dealt with in a new custodian, making it easy to "clean-up" all resources that might have been left open by the handler (e.g., open ports). The following extends the "echo server" example with such a custodian use:
#lang racket (define listener (tcp-listen 12345)) ;; per-connection handler (define (handler in out) (copy-port in out) (close-output-port out)) (let echo-server () (define-values (in out) (tcp-accept listener)) (thread (λ () (let () (parameterize () (handler in out) (custodian-shutdown-all c))))) (echo-server))
Custodians, combined with the memory accounting feature of the 3m garbage collector, and several added runtime parameters that control more aspects of the runtime, make it possible to create fully safe sandboxed execution contexts. The racket/sandbox
library provides this kind of functionality in a simple way. The following example creates a read–eval–print loop (REPL) server on the specified port; connecting to this port will look like a plain Racket REPL, except that the evaluation is subject to the various protection aspects of the sandbox. For example, it is not possible to access the file system from this REPL, create network connection, run subprocesses, or use too much time or memory. (In fact, this REPL is safe enough to be given out publicly.)
#lang racket (require racket/sandbox) (define e (make-evaluator 'racket/base)) (let-values () (parameterize ( ) (read-eval-print-loop) (fprintf o "\nBye...\n") (close-output-port o)))
Web and network programming
The next example implements a web server using the web-server/insta
language. Each time a connection is made to the server, the start
function is called to get the HTML to send back to the client.
#lang web-server/insta ;; A tiny "hello world" web server (define (start request) (response/xexpr '(html (body "Hello World"))))
Racket also includes the functions needed to write scrapers and robots. As an example, the following function lists the Google results for a search string.
#lang racket ;; Simple web scraper (require net/url net/uri-codec) (define (let-me-google-that str) (let* ( ) (regexp-match* rx (get-pure-port (string->url u)))))
The library also includes support for protocols other than http:
#lang racket ;; Sending a timed email alert from racket (require net/sendmail) (sleep (* (- (* 60 4) 15) 60)) ; wait 3h 45m (send-mail-message (getenv "EMAIL") "Parking meter alert!" (list (getenv "EMAIL")) null null '("Time to go out and move the car."))
Graphics
Graphic capabilities come in several different flavors that are intended for different audiences. The 2htdp/image
library provides convenient functions for constructing images. This library is mainly used by students in How to Design Programs (HtDP) based courses. In the following example, a sierpinski
function is defined and called (at the same time) to generate a Sierpinski triangle of depth 8.
#lang racket ;; A picture (require 2htdp/image) (let sierpinski () (if (zero? n) (triangle 2 'solid 'red) (let () (freeze (above t (beside t t))))))
DrRacket editors can contain images, and DrRacket displays image values just like any other type of value (such as integers or lists). Running the above program, for example, actually displays a Sierpinski triangle, which can be cut and pasted into another program.
The plot
library constructs image values for more mature audiences and needs. For example, the following program plots the sum of two (three-dimensional) Gaussians, as concentric, partially transparent surfaces:
#lang racket ;; Visualize a sum of two 3D Gaussians as concentric isosurfaces ;; Note: this example requires Racket 5.2 or later (require plot) ;; Returns an R x R x R -> R Gaussian function centered at (cx,cy,cz) (define ((gaussian cx cy cz) x y z) (exp (- (+ (sqr (- x cx)) (sqr (- y cy)) (sqr (- z cz)))))) ;; Lifts + to operate on three-argument functions (define ((f3+ g h) x y z) (+ (g x y z) (h x y z))) ;; Constructs an image value representing the sum of two Gaussians (plot3d (isosurfaces3d (f3+ (gaussian 0 0 0) (gaussian 1.5 -1.5 0)) -1 2.5 -2.5 1 -1 1 #:label "g")) ; labeling adds a legend
Here, the isosurfaces3d
function requires a three-argument function for its first argument, which the curried f3+
supplies. Besides constructing image values, plot
can also write files in Portable Network Graphics (PNG), Portable Document Format (PDF), PostScript and Scalable Vector Graphics (SVG) formats.
GUI programming
Racket implements a portable GUI layer which the libraries mentioned above build on. It is implemented via the native Windows application programming interface (API), via Cocoa on macOS, and via GTK+ on Linux and others. The Racket API is a class-based toolkit, somewhat related to wxWidgets which was used originally.
The following simple guessing game demonstrates coding with the GUI toolkit. The frame%
class implements a top-level window, and button%
implements a button. The check
function defined here produces a function that is used for the button's callback action.
#lang racket/gui ;; A GUI guessing game (define secret (random 5)) (define f (new frame% )) ; toplevel window (define t (new message% )) (define p (new horizontal-pane% )) ; horizontal container (define ((make-check i) btn evt) (message-box "." (cond )) (when (= i secret) (send f show #f))) ; success => close window (for () ; create all buttons (make-object button% (format "~a" i) p (make-check i))) (send f show #t) ; show the window to start the application
The GUI can be hand-coded in this way or with the help of a GUI designer program available on PLaneT.
Slideshow
Slide-based presentations can also be developed in Racket using the slideshow
language, much like Beamer, but with Racket's programming facilities. Elements of the slides are pictures that can be combined.
For example, the following program displays in full-screen a title slide, followed by a slide with some pictures. The vc-append
and hc-append
functions combine pictures vertically and horizontally, respectively, and centered on the other axis.
#lang slideshow (slide (text "Slideshow" 'roman 56) (text "Making presentations in Racket" 'roman 40)) (slide #:title "Some pictures" (apply vc-append (for/list () (define (scale+color p c) (colorize (scale p (/ (add1 i) 5)) c)) (hc-append (scale+color (filled-rectangle 100 50) "darkblue") (scale+color (disk 100) "darkgreen") (scale+color (arrow 100 (/ pi 6)) "darkred") ))))
Extension packages also exist on PLaneT, for example to include LaTeX elements.
Foreign function interface
Racket features a foreign function interface that is based on libffi. The interface allows writing unsafe low-level C-like code, that can allocate memory, dereference pointers, call out to functions in shared libraries, and send out callbacks to Racket functions (using libffi closures). The core implementation is a thin layer atop libffi (written in C), and the full interface is then implemented via Racket code. The interface uses macros extensively, resulting in an expressive Racket-based interface description language. This language has a number of useful features, such as uniform representation for higher-order functions (avoiding the pitfalls when callbacks and callouts are different), struct definitions that are similar to plain Racket structs, and custom function types that can represent input and output pointers, implicit arguments (e.g., an argument that provides the number of elements in a vector that is passed as another argument). By using this interface to access underlying GUI toolkits, Racket implements its own GUI layer, in Racket.
The FFI can be used in a number of different ways: from writing a complete glue layer for a library (as done for Racket's OpenGL binding), to quickly pulling out a single foreign function. An example of the latter approach:
#lang racket/base ;; Simple use of the FFI (require ffi/unsafe) (define mci-send-string (get-ffi-obj "mciSendStringA" "Winmm" (_fun _string -> ))) (mci-send-string "play sound.wav wait")
Language extensions
Racket's most notable feature is its ability to build new domain-specific and general-purpose languages. This is the result of combining a number of important features:
- a flexible module system that is used for linking code and for namespace management,
- an extensive macro system—functioning as a compiler-API—that can create new syntactic forms,
- a rich runtime system, providing features that language implementors can use, like (composable, delimited) continuations, resource management, etc.,
- a way to specify (and implement) parsers for new language syntaxes.
The module system plays an important role in combining these features, and making it possible to write code that spans across a number of modules, where each can be written in a different language.
Such languages are used extensively in the Racket distribution and in user libraries. In fact, creating a new language is so straightforward, that there are some languages that have less than a handful of uses.
Racket comes with a number of useful languages, some are very different from Racket's default language.
Scribble
Scribble, Racket's documentation system, comes in the form of a number of languages that are used to write prose. It is used for Racket's documentation, as well as writing books and articles. Actually, rather than a single "scribble" language, it is a family of (very similar) dialects, each for a different purpose.
To run the following example, copy it into DrRacket and click one of the two scribble rendering buttons that will appear (PDF rendering requires pdfTeX). Alternatively, use the scribble
executable on the file.
#lang scribble/base @; Generate a PDF or an HTML document using `scribble' @(require (planet neil/numspell)) @title{99 Bottles of Beer} In case you need some @emph{blah blah} in your life. @(apply itemlist (for/list () (define N (number->english n)) (define N-- (number->english (sub1 n))) @item{@string-titlecase bottles of beer on the wall, @N bottles of beer. Take one down, pass it around, @N-- bottles of beer on the wall.}))
The most striking feature of the Scribble languages is their use of a new syntax, which is designed specifically for textually rich code. The syntax allows free-form text, string interpolation, customizable quotations, and is useful in other applications such as preprocessing text, generating text, and HTML template systems. Note that the syntax extends plain S-expressions, and is implemented as an alternative input for such expressions.
#lang scribble/text Hi, I'm a text file -- run me. @(define (thrice . text) @list{@text, @text, @text}) @thrice{SPAM}! @thrice{HAM}!
Typed Racket
Typed Racket is a statically typed variant of Racket. The type system that it implements is unique in that the motivation in developing it was accommodating as much idiomatic Racket code as possible—as a result, it includes subtypes, unions, and much more. Another goal of Typed Racket is to allow migration of parts of a program into the typed language, so it accommodates calling typed code from untyped code and vice versa, generating dynamic contracts to enforce type invariants. This is considered a desirable feature of an application's lifetime stages, as it matures from "a script" to "an application", where static typing helps in maintenance of a large body of code.
#lang typed/racket ;; Using higher-order occurrence typing (define-type Str-or-Num (U String Number)) (: tog ((Listof Str-or-Num) -> String)) (define (tog l) (apply string-append (filter string? l))) (tog (list 5 "hello " 1/2 "world" (sqrt -1)))
Lazy Racket
The lazy
language is a language with lazy evaluation semantics, similar to Haskell. In the following example, fibs
is an infinite list which 1000th element will not be computed until its value is needed for the printout.
#lang lazy ;; An infinite list: (define fibs (list* 1 1 (map + fibs (cdr fibs)))) ;; Print the 1000th Fibonacci number: (print (list-ref fibs 1000))
Logic programming
Racket comes with three logic programming languages: Racklog, a Prolog-like language; a Datalog implementation; and a miniKanren port. Unlike the Scribble syntax, the first two of these languages use an all-new syntax rather than an extension of S-expressions. If used it in DrRacket, it provides proper highlighting, the usual host of tools check syntax, and a Prolog/Datalog REPL.
#lang datalog ancestor(A, B) :- parent(A, B). ancestor(A, B) :- parent(A, C), D = C, ancestor(D, B). parent(john, douglas). parent(bob, john). ancestor(A, B)?
Education tools
The PLT group which develops Racket has traditionally been involved in education at all levels. One of the earliest research ideas that the group promoted is the use of language levels, which restrict new students while providing them with helpful error messages that fit the student's level of knowledge. This approach is heavily used in How to Design Programs (HtDP), the textbook that several PLT developers have authored, and in the ProgramByDesign project. The following program uses the htdp/bsl
—the "beginning student language". It uses the 2htdp/image
library for creating pictures in the teaching languages, and the 2htdp/universe
library for interactive animations.
#lang htdp/bsl ;; Any key inflates the balloon (require 2htdp/image) (require 2htdp/universe) (define (balloon b) (circle b "solid" "red")) (define (blow-up b k) (+ b 5)) (define (deflate b) (max (- b 1) 1)) (big-bang 50 (on-key blow-up) (on-tick deflate) (to-draw balloon 200 200))
ALGOL
Racket comes with a full implementation of the ALGOL 60 language.
#lang algol60 begin integer procedure SIGMA(x, i, n); value n; integer x, i, n; begin integer sum; sum := 0; for i := 1 step 1 until n do sum := sum + x; SIGMA := sum; end; integer q; printnln(SIGMA(q*2-1, q, 7)); end
Plai and plai-typed
#lang plai
#lang plai-typed
Another supported language is plai which like racket can be typed or untyped. "Modules written in plai export every definition (unlike scheme)." "The Typed PLAI language differs from traditional Racket most importantly by being statically typed. It also gives some useful new constructs: define-type, type-case, and test."
Creating languages
Finally, the following example is an implementation of a new language:
#lang racket (provide (except-out (all-from-out racket) #%top #%app) (rename-out )) (define-syntax-rule (top . x) 'x) (define-syntax-rule (app f . xs) (if (hash? f) (hash-ref f . xs) (f . xs)))
This language:
- provides everything from the
racket
language, so it is a somewhat similar variant, - except for two special "hook macros" that implement unbound variable lookup and function calls, instead of these, new forms are provided to
- implicitly quote all unknown variables
- allow hash tables to be used as functions, where the arguments are used for hash-table lookup.
If this code is stored in a mylang.rkt
file, it can be used as follows:
#lang s-exp "mylang.rkt" ; sexpr syntax, using mylang semantics (define h (make-hasheq)) (hash-set! h A B) ; A and B are self-evaluating here (h A) ; the hash table is used as a function
References
- Tobin-Hochstadt, S.; St-Amour, V.; Culpepper, R.; Flatt, M.; Felleisen, M. (2011). "Languages as Libraries" (PDF). Programming Language Design and Implementation.
- ^ PLaneT: Racket's centralized package distribution system
- "Rebuilding Racket's Graphics Layer". 2010-12-08. Archived from the original on 2013-02-02. Retrieved 2013-07-07.
- Barzilay, E. (2009). "The Scribble Reader" (PDF). Scheme and Functional Programming.
- Tobin-Hochstadt, S.; Felleisen, M. (2008). "The Design and Implementation of Typed Scheme". Principles of Programming Languages.
- Tobin-Hochstadt, S.; Felleisen, M. (2006). "Interlanguage Migration: From Scripts to Programs". Dynamic Languages Symposium.
- "1 PLAI Scheme".
- Krishnamurthi, Shriram. "Programming Languages: Application and Interpretation." Programming Languages: Application and Interpretation. Brown University, n.d. Web. 14 Mar. 2016. <http://cs.brown.edu/courses/cs173/2012/book/>.
- Note that
#%app
is a macro that is used in all function calls, making this language not too efficient, as every function call incurs an added condition. Also, the macro evaluates the function expression twice, so it should not be taken as an example of good macro-programming.
- As of this edit, this article uses content from "Racket", which is licensed in a way that permits reuse under the Creative Commons Attribution-ShareAlike 3.0 Unported License, but not under the GFDL. All relevant terms must be followed.