Live data from Hacker News

A Friendly Introduction to Racket

geometridae.bearblog.dev

71–80 of 195 posts

Re: A Friendly Introduction to Racket

#71
My first language, 1980 in CMU, was Pascal... quickly followed by LISP in CS/AI courses and C for EE courses. I was a big fan of MacLisp at the time, the MIT version that GLS worked on (could see his comments all over the sources). Of course GLS moved on to Scheme and wrote a few definitive papers on closures. Yeah, that was before PC's everywhere... a loooong time ago. (C++ came years and years afterwards, not a fan. I would have stayed with hardware if the ++ version of C was forced on me all those years ago.)

GLS moved to CMU in the early 80's... I remember taking "Comparative Programming Languages" from him. Good teacher and impressive guy. In addition to the obvious, he also covered SNOBOL and APL in that course. Memories :-)

Re: A Friendly Introduction to Racket

#72
post #19
post #8

Earlier quoted context omitted.

Homoiconicity.

I don’t find it appealing when everything looks the same irrespective of purpose and context.

You can read the words, you know? Together with proper indentation that almost makes it look like Python, there's no way you can get lost in Lisp.

Re: A Friendly Introduction to Racket

#73

Nothing against Lisp, but to correct the record: > For decades, Lisp was the language of artificial intelligence. [...] Then came the "AI winter," funding dried up, and Lisp went from star to cult language. Lisp had fallen from relevance before then. Only the United States was still using it, and mostly out of technical debt and a stubborn refusal to move on. Prolog displaced it in the late 1970s, and even within the…

And then mini/microKanren put Prolog in its rightful place: that of a useful DSL instead of a poor general purpose language.

Re: A Friendly Introduction to Racket

#74

I've been designing my own small language runtime in Rust (VM + JIT + AOT backends) mostly as a way to actually understand tradeoffs compiler authors make instead of just reading about them. Racket's approach to macros and language-oriented programming is one of the things I keep coming back to as a reference curious how much of that flexibility comes at a real runtime cost vs. being mostly a compile-time abstraction…

I can answer that for Common Lisp, specifically the SBCL implementation (there's several others). It compiles every function to native code (you can even inspect the assembly with `disassemble`). Macros are executed before code is compiled. Hence, once you've compiled a function, the macro disappears since its only role is to generate the expressions that are going to actually be compiled and then executed.

For example, here's a simple CL macro:

    (defmacro defer (cleanup &body action)
         `(unwind-protect (progn ,@action) ,cleanup))
`unwind-protect` is like a `try/finally` in other languages, and I used that above to create something similar to `defer` in Go/Zig which is related to it, but with the operands inverted.

The ` symbol is a quasiquote. Unlike quote `'` it lets you unquote symbols inside with the , operator. That's why you'll always see a bunch of '`' and ',' in macros.

The @, thing is a "spread" (looks different in Racket from what I saw in the post, which used `...`). It just spreads whatever was on the list in the place you put that on, so if `action` is `(p 1) (p 2)`, then `(progn ,@action)` becomes `(progn (p 1) (p 2))`.

You can inspect what the actual code that will be compiled looks like with `macroexpand`:

    CL-USER> (macroexpand '(defer (cleanup) (do-something)))
    (UNWIND-PROTECT (PROGN (DO-SOMETHING)) (CLEANUP))
`progn` is a "special operator" that's needed when you want more than one expression to be evaluated in order.

Example calling the macro:

    CL-USER> (defer (print "done") 
               (print "hello")
               (print "again"))

    "hello" 
    "again" 
    "done"
As you can see, it executed the deferred expression last.

We can prove that macros disappear after compile-time with an example:

    CL-USER> (disassemble (lambda (x) (+ x x)))
    ; disassembly for (LAMBDA (X))
    ; Size: 36 bytes. Origin: #x8005F70664                        ; (LAMBDA (X))
    ; 64:       AA0A40F9         LDR R0, [THREAD, #16]            ; binding-stack-pointer
    ; 68:       AA0B00F9         STR R0, [CFP, #16]
    ; 6C:       EA030CAA         MOV R0, R2
    ; 70:       EB030CAA         MOV R1, R2
    ; 74:       297E80D2         MOVZ TMP, #1009
    ; 78:       5E6B69F8         LDR LR, [NULL, TMP]              ; SB-KERNEL:TWO-ARG-+
    ; 7C:       DE130091         ADD LR, LR, #4
    ; 80:       C0031FD6         BR LR
    ; 84:       E00120D4         BRK #15                          ; Invalid argument count trap

You can see the Assembly is very simple for `(+ x x)` (the ADD instruction plus a bunch of stack/error maintenance).

If we instead had a macro that did this:

    (defmacro my-macro (x) `(+ ,x ,x))
And a function used that:

    (defun f (x) (my-macro x))
Now, disassembling the function:

    CL-USER> (disassemble #'f)
    ; disassembly for F
    ; Size: 36 bytes. Origin: #x8005C00374                        ; F
    ; 74:       AA0A40F9         LDR R0, [THREAD, #16]            ; binding-stack-pointer
    ; 78:       AA0B00F9         STR R0, [CFP, #16]
    ; 7C:       EA030CAA         MOV R0, R2
    ; 80:       EB030CAA         MOV R1, R2
    ; 84:       297E80D2         MOVZ TMP, #1009
    ; 88:       5E6B69F8         LDR LR, [NULL, TMP]              ; SB-KERNEL:TWO-ARG-+
    ; 8C:       DE130091         ADD LR, LR, #4
    ; 90:       C0031FD6         BR LR
    ; 94:       E00120D4         BRK #15                          ; Invalid argument count trap
Same thing exactly.

I don't know Racket, but knowing it can compile to binary, I expect macros in Racket would work exactly the same.

Re: A Friendly Introduction to Racket

#75

Earlier quoted context omitted.

> From the perspective where local reasoning is the most desirable property a language can have That's a perspective. If you're looking for a low-level language, then Scheme isn't it. (Forget iconicity - Scheme is garbage-collected. And supports continuations!) If you don't program in machine code - which would maximize local reasoning - then you must know the language with the Correct balance of local reasoning and…

https://prescheme.org/ Pre-Scheme is a statically typed dialect of the Scheme programming language, combining the flexibility of Scheme with the efficiency and low-level machine access of C. The compiler uses type inference, partial evaluation, and other correctness-preserving transformations to compile a subset of Scheme into C with no additional runtime overhead. This makes Pre-Scheme a viable alternative to C for…

Fair point.

Re: A Friendly Introduction to Racket

#76
post #5
post #2

any time the topic of racket comes up, i wonder if there are any interesting apps i could explore. but all i find is libraries and dev tools: https://awesome-racket.com/

it's an academic language

The co-creator of Scheme is also co-author of Structure and Interpretation of Computer Programs[0]. Namely, Gerald Jay Sussman[1], the Panasonic Professor of Electrical Engineering at the Massachusetts Institute of Technology (MIT).

In teaching our material we use a dialect of the programming language Lisp. We never formally teach the language, because we don’t have to. We just use it, and students pick it up in a few days. This is one great advantage of Lisp-like languages: They have very few ways of forming compound expressions, and almost no syntactic structure. All of the formal properties can be covered in an hour, like the rules of chess. After a short time we forget about syntactic details of the language (because there are none) and get on with the real issues—figuring out what we want to compute, how we will decompose problems into manageable parts, and how we will work on the parts. Another advantage of Lisp is that it supports (but does not enforce) more of the large-scale strategies for modular decomposition of programs than any other language we know. We can make procedural and data abstractions, we can use higher-order functions to capture common patterns of usage, we can model local state using assignment and data mutation, we can link parts of a program with streams and delayed evaluation, and we can easily implement embedded languages. All of this is embedded in an interactive environment with excellent support for incremental program design, construction, testing, and debugging. We thank all the generations of Lisp wizards, starting with John McCarthy, who have fashioned a fine tool of unprecedented power and elegance.

[0]: https://sarabander.github.io/sicp/

[1]: https://en.wikipedia.org/wiki/Gerald_Jay_Sussman

Re: A Friendly Introduction to Racket

#77

Earlier quoted context omitted.

What makes this a desirable feature? From the perspective where local reasoning is the most desirable property a language can have, how does homoiconicity support that? I honestly am curious. I've seen a few examples presented for it, but they always seem like bad software engineering to me. Where's an example that does something in a cleaner way than alternatives present in other languages while remaining compatible…

Homoiconicity makes writing macros easy. If you don't like it, you can try https://rhombus-lang.org/ that is build on Racket and also has macros but uses a Python-like syntax.

Bicameral, Not Homoiconic https://parentheticallyspeaking.org/articles/bicameral-not-h...

Re: A Friendly Introduction to Racket

#78

> no special syntax for anything. (list '(1. . #\#) -5/6+7.s-8i `(1 ,@2) 1@1 ;hmmm, no unquote splicing comma ;-) 10# ;surprised? (list #i+1 +1i 1+i) ;complicated or complex? #e-1e10i ;Old MacDonald? "(* 9 10)" #())

You forgot hash table and regular expression literals.

Re: A Friendly Introduction to Racket

#80

Earlier quoted context omitted.

https://prescheme.org/ Pre-Scheme is a statically typed dialect of the Scheme programming language, combining the flexibility of Scheme with the efficiency and low-level machine access of C. The compiler uses type inference, partial evaluation, and other correctness-preserving transformations to compile a subset of Scheme into C with no additional runtime overhead. This makes Pre-Scheme a viable alternative to C for…

Also, CRUNCH from Chicken Scheme: https://wiki.call-cc.org/eggref/6/crunch

Ah, thank you. It slipped my mind.

CRUNCH is an embedded compiler for a statically typed subset of R7RS Scheme, generating C code. The compiler uses type inference to decorate the code with type information without requiring declarations. CRUNCH can be used to translate embedded Scheme code sections, whole programs or multiple source modules into standalone executables or compiled code that can be invoked from Scheme.

The generated C code uses a small runtime-system contained completely in a single C header file. Reference counting is used for managing aggregate data like strings which removes the need for full tracing garbage collection or manual memory management while still having a relatively small overhead.

Since more or less a direct translation of Scheme to C is done, the generated code should run at roughly the same performance as C. No type-checking takes place as the types of all values have been inferred at compile time, and values are not tagged. With the exception of reference counted objects there is no additional runtime overhead and Scheme and C can directly interchange data. This makes CRUNCH very appropriate for writing programs that need a maximum of speed or that are target for constrained environments like deeply embedded systems. The code is portable to all systems that at least have a C compiler.

UNICODE strings are supported and can optionally be disabled for improving performance and reducing code size.

CRUNCH is heavily inspired by PreScheme, the low-level compiler that is originally part of the Scheme48 project. In fact, CRUNCH can be considered a modern reimplementation of PreScheme written in and for use with CHICKEN.

See also:

  Crunch – a Scheme compiler with a minimal runtime (more-magic.net)
 190 points by sjamaan on Dec 17, 2024 | hide | past | favorite | 72 comments
https://news.ycombinator.com/item?id=42440767
Post reply on HN