
This is a fantastic article, and it asked and answered questions I didn’t know how to ask.

I’ve been asked the question “What are the practical uses for DSLs?” a lot when doing Racket presentations. Thank you so much for that, Matthew!

By the way, the videos of my presentations at FOSDEM 2019 on How to make languages in Racket are available here: https://fosdem.org/2019/schedule/event/jsonwhendsl/ https://fosdem.org/2019/schedule/event/makeownlangracket/

thanks @samth i will take a more in-depth look at his code then.

Thank you, Jérôme!

is there a way to support response
from (require web-server/http/response-structs)
in typed/racket? I tried wrapping the struct in an opaque require/typed
using can-be-response?
but this fails: can-be-response?: contract violation
any-wrap/c: Unable to protect opaque value passed as `Any`
value: #<response>
This warning will become an error in a future release.
in: the 1st argument of
a part of the or/c of
(or/c
struct-predicate-procedure?/c
(-> Any boolean?))
contract from:
(interface for can-be-response?)

Thank you, Jerome!

I think you will need to use a more specific predicate. Can you use response?

@jerome.martin.dev I am also exploring minimalism, and living meaningfully

@mbutterick two thoughts on the presentation: 1. I think the lindemayer example language would fit nicely in this document, especially since it generates cute pictures and comes with a tutorial paper 2. I think an example earlier on would helpful, perhaps even in the first few paragarphs.

Oh neat, I live right next to Indiana University, so if Daniel Friedman is still there, I could theoretically go say hi.

@abbyrjones72 Dan is indeed still here, and if you’re into Racket there’s lots of us here and you should definitely come say hi

Perhaps I will :slightly_smiling_face:

I’ve thought about applying to the PhD program at the public health school, but I am not motivated lol

Luddy hall is very fancy, and you’re welcome to drop by my office anytime

ty samth :slightly_smiling_face:

So, it’s Hoosier time here? I went to Purdue University :slightly_smiling_face:

I went there for a year

At age 38, I felt like I was 20 years late for the prom, but Dr. Cover was my favorite instructor. Philosophy :slightly_smiling_face:

never too late for some good college classes!

lol

I’m 36 and I’ve debated whether I should consider masters or PhD in PL or computational science topics, it would be wonderful but it’s debatable whether it’s a wise course of action these days…

I kept it going, but at other schools.

@abmclin I was 44 when I started my masters and 45 when I finished. Hasn’t produced anything in the way of work, but I feel accomplished

that’s what counts! and congratulations on your masters

why ty!

Question: If anyone is familiar with the SICP Exercise 1.5, we are analyzing this:
(define (p) (p))
(define (test x y)
(if (= x 0) 0 y))
(test 0 (p))
But I am not sure what is happening here. Should the first line be (define (p (p)) if we are defining a procedure p that takes procedure p?

It’s been a long time since I’ve looked at SICP. The first line is defining a procedure p
. In the body of p
, p
is being applied, since it’s surrounded by parentheses, so it is basically calling itself

oh

if you tried it out, it would recur forever since it’s calling itself

yes

I saw that lol

would this be an example of recursion without a base case?

it seems that (test 0 (p))
will never return

yes, that would a good example, it doesn’t have any base case so it never terminates

okay, that helps me understand it. tyvm!

it’s equivalent to writing (define p (lambda () (p)))
, which reveals that p is called inside the lambda

okay i will need to think about that

I haven’t studied lambda yet at all

It’s the minimal unit in Scheme languages. It’s unique role is to create a new procedure. I won’t spoil SICP, but keep in a corner of your mind that lambda is a bit magical. It’s one of the rare keywords (usually) defined directly in Scheme interpreters (so not written in scheme, but in the base language used to implement Scheme) because it’s the keyword that allows every other part of Scheme to exist. You could basically reduce any program to only lambda
calls.

oooh I like magical stuff :slightly_smiling_face:

I guess that’s also why Racket, and a lot of other Lisp languages, use lambda as a logo :racket:

the idea of lambda
is borrowed from Alonzo Church’s lambda calculus, it can be thought of an abstract description of how a function is made of parameters and a body. The function is used by giving it arguments which are evaluated and bounded to corresponding variables in the body. Scheme allows you to directly work with lambda
s so you can build complicated things with just lambda
s

The interesting thing is a lambda
can be evaluated different ways, which is why you see discussion about applicative and normal evaluation in SICP, though my understanding is those terms are not standard in current programming language literature, they use different names. SICP was written a long time ago so things have moved long way since then

oh…I was devoting an entire blog entry to Applicative/Normal and hesitating…maybe I should just move on and get to the meaty stuff

are there more current explanations I can read?

it’s not really an issue nowadays, apart from research fields

okay

I won’t worry too much about it, I’ll look for a decent explanation for you though

@abbyrjones72 this is not bad overview, https://en.wikipedia.org/wiki/Evaluation_strategy

But there’s one interesting thing you could talk about when you’ll be finished with SICP and will try macros (it’s not for now!): In Racket, procedures are applied in the classic order (arguments first, procedure after), but macros are applied in reverse (transformation first, arguments after). But it’s a bit complicated for a beginner.

@abmclin I quoted your explanation on my blog if that is okay

it’s fine with me @abbyrjones72

ty

Re. 1 IMHO lindenmayer as cool as it is has too much of an academic vibe so it really depends on the desired audience of BR

@githree do you think the language has an academic vibe (drawing trees for biology) or the paper/racket presentation of it has an academic vibe?

mostly the former - and nothing wrong with that! But reading Matthew’s “why lop…” post I feel it is mostly targeted at the industry (html, riposte, etc.)

So I’ve been working on the classic perfect/abundant/deficient aliquot sum problem a bit and was experimenting with a couple of ways of completing it. (require racket/stream)
(require threading)
(require memoize)
(define (evenly-divisible? num denom)
(equal? 0 (remainder num denom)))
(define/memo (factors n)
(stream-filter (curry evenly-divisible? n)
(in-range 1 n)))
(define (aliquot-2-all n)
(stream-fold + 0
(factors n)))
; this one seems to run significantly faster than
; the two step filter/reduce
(define (aliquot-sum-1 n)
(stream-fold (curry aliquot-foldl n) 0 (in-range 1 n)))
(define (aliquot-foldl max acc n)
(cond
[(evenly-divisible? max n) (+ acc n)]
[else acc]))
(provide classify)
(define (classify n)
(define al-sum (aliquot-sum-1 (abs n)))
(cond
[(equal? al-sum n) 'perfect]
[(< al-sum n) 'deficient]
[(> al-sum n) 'abundant]))

I’m wondering why the filter/foldl is so much slower than the flat foldl
when I’m using a stream

It’s ~twice as slow to filter/foldl

if anyone knows about make-screen-bitmap
vs. make-bitmap
, please take a look at this pull request: https://github.com/racket/plot/pull/51

@slmn.sttr.65 has joined the channel

@ben I think @mflatt is likely to know the most there

he commented a few minutes ago :)

Does anyone know if there is anything out there in Racket to do face recognition? If not, is there anything that could be a stepping stone to that?

I agree about the focus. I was mostly thinking of it as one of many examples but I can certainly see how it might come off the wrong way

your best bet would be probably with tensorflow binding that apparently few people have started working on recently: https://groups.google.com/forum/#!searchin/racket-users/tensorflow%7Csort:date/racket-users/SM83PPLlEL4/loe1i8FZAwAJ



I’ve been making some dirt-simple #langs that walk over modules and add bindings to them manipulating the AST rather than just defining macros to expand. We needed to do this because in one of the languages we’re planning to write, we need to replace identifiers (they have to be changed to applications of a lookup form to respect a security property of the language). Tiny progress here: https://github.com/kmicinski/tinylangs/blob/master/tinylang1.rkt :slightly_smiling_face:

Any input or more examples is always appreciated, but this taught me a lot. I’ve only ever written macros that expand forms using things like syntax-case, never manipulating the AST directly, so playing around with the expander was really helpful..

One thing I don’t really “get” is how when you use with-syntax
, it introduces a binding that you can then use in quote-syntax. So for example, if you define x
using with-syntax
, then #'x
is valid (where ’ is backtick but making slack-friendly). This is different than if I just did a regular quasiquote, where (quasiquote x) would just be the symbol x. Why isn’t it the case that #'x
for quote-syntax is just the identifier x?

@krismicinski is your question “why did they design syntax-case
/syntax
that way”, or “how does that work”?

I guess I’m trying to reconcile the differences between syntax-quote and regular quasiquoting, since I feel like I’m misunderstanding

so I suppose a bit of both, largely the second.

Wait - syntax
and syntax-quote
is different. Do you mean syntax
?

First, one thing to know is that there’s quote-syntax
which does what quote
does

ie, (quote-syntax x)
is exactly the identifier x

right, ok

So to be precise about it, on this line here: https://github.com/kmicinski/tinylangs/blob/master/tinylang1.rkt#L26

I am surprised this expands to the syntax for transformed
rather than the identifier transformed

Second, the basic idea is that “pattern variables” bound by syntax-case
are used in the “template” created by the syntax
form

this is to support “macro by example”, as you see in syntax-rules
as well

Further, with-syntax
is just a trivial wrapper around syntax-case

ah, ok, that last thing you said makes it make more sense

So it looks for pattern variables first and then defaults to an identifier if not found?

something like that?

but really syntax-case
is just a combination of a pattern matcher and binding pattern variables, which are then available in things constructed with syntax

I see, that does make more sense.

you could have a pattern matcher that worked more like match
, and then have to use quasisyntax
to construct the output

this is what Common Lisp macros look like, somewhat

I see. I feel like I’ve got not a ton of intuition for this yet, but that helps!

sounds like I should mostly read more about syntax-case


We need a beginners guide to lists in Racket.

What do you all do to combat those “why should I bother with this?” moments?

Do you use scribble/srcdoc
for in-source documentation? Or do you always use a new file for documentation?

I always make a <package-name>.scrbl
. I only sometimes use scribble/srcdoc
in .rkt
files, to create doc submods that I include in the main .scrbl
using @include-extracted
.

@abbyrjones72 say “good point” and not bother with it, usually

I do that probably more often than I should

@abbyrjones72 It might be important to figure out who thinks you should bother and what their reasons are. Sometimes the reasons are hidden. Sometimes there aren’t really good reasons, it’s just inertia.

Is it specifically something you’re trying to learn that seems to be pointless? I think in that situation, I skim it so I can recall the terminology involved, and if someday I realize it would help, I look it up then.

@plragde I completely understand the inertia part of this. I have been pushing every day to work through it, and also work through the difficult concepts. It is worth it, even if I never work as a programmer again. I need to deprogram myself into thinking this is a way into the 20 somethings rat race. I love this language, and LOP, the more I read about it.
Thanks for asking the question, because it made me think.

I’m trying and failing to get this to type-check: #lang typed/racket/base
(struct (A) Prefix ([x : A]))
(struct (A) Term
([qual : (Prefix A)]
[base : (U (Term A) A)]))
(: get-base (All (A) (-> (Term A) A)))
(define (get-base term)
(let ([maybe-base (Term-base term)])
(cond [(Term? maybe-base)
(get-base maybe-base)]
[else
maybe-base])))
Does anyone know how to do this?

@hoshom I’m guessing the problem is the (U (Term A) A)
part

I think so

the error I get is: Type Checker: Polymorphic function `get-base' could not be applied to arguments:
Argument 1:
Expected: (Term A)
Given: (U (Term A) (∩ #(struct:Term ((Prefix Any) Any)) A))
Result type: A
Expected result: A
in: (get-base maybe-base)

as a general rule, avoid unions between polymorphic types that aren’t disjoint

they almost never work the way you want them to

Hmm I thought this would work since it’s kind of similar to what a list looks like.

lists use a special singleton null value as the end-of-list marker, but the (U (Term A) A)
type is a union between two sets, not between a set and a singleton

someone could instantiate A
to (Term Foo)
, with a resulting union type of (U (Term (Term Foo)) (Term Foo))
- and then it’s ambiguous which case it is

Oh! I knew I must be missing something, and yes, you’re right.

So I think I got my workaround: All I have to do is wrap the base in a struct

Yup!

So (U (Term A) (Base A)
works, my function now returns (Base A)

I got a working version of your thing:

thanks!

#lang typed/racket/base
(struct (A) Prefix ([x : A]))
(struct (A) Primitive-Term
([value : A]))
(struct (A) Compound-Term
([qual : (Prefix A)]
[base : (Term A)]))
(define-type (Term A)
(U (Primitive-Term A) (Compound-Term A)))
(: get-base (All (A) (-> (Term A) A)))
(define (get-base term)
(cond [(Primitive-Term? term)
(Primitive-Term-value term)]
[(Compound-Term? term)
(get-base (Compound-Term-base term))]))

as a rule of thumb: be suspicious of (U ... type-variable ...)

haha

my version right now’s a bit simpler so I’m going with it: #lang typed/racket/base
(struct (A) Prefix ([x : A]))
(struct (A) Term
([qual : (Prefix A)]
[base : (U (Term A) (Base A))]))
(struct (A) Base ([val : A]))
(: get-base (All (A) (-> (Term A) (Base A))))
(define (get-base term)
(let ([maybe-base (Term-base term)])
(cond [(Term? maybe-base)
(get-base maybe-base)]
[else
maybe-base])))

oh yup that’s a better way

By the way the reason this happened was because I meant A
to actually be “one of several subtypes of a struct”, but if I just use the parent struct in the type, I don’t get to say “function X works with a term of only a subtype of the struct”. So I just put type variables everywhere :smile:

rather, “a parent struct or any subtype”

oh that makes sense :p