You can't use local in BSL. :-(

I don't know if this is a feature request or just a whine, but I would love to be able to introduce local before list abbreviations.

Unfortunately, you can't use local in BSL, because the macro raises an error if you have a define that's not on the top level. I can use let, but local is especially nice, because it doesn't involve new syntax. Students just keep using the define they used at the top level, but hide the scope inside a function (or an expression or whatever). In particular, it's nice that local lets them use define to name constants or functions, whereas let would require the introduction of lambda for that.

I looked at the code to see if I could easily fix the problem, but the code is quite dense.

I similarly was trying to figure out if I could modify define-struct in two ways:

  1. I wanted students to be able to put signatures for fields: (define-struct student ([first String] [last String] [grade Natural]) and have signatures provided for make-student and the selectors.

  2. I wanted to auto-create something like lenses for structs. Especially when you're trying to create worlds, you spend a lot of time copying state. A handler may want to modify one or two fields in a struct that has several, so you (make-struct (struct-field1 orig-struct) (struct-field2 orig-struct) ... (f (struct-fieldn orig-struct))) and you forget what you were trying to do, or your code gets long and you can't see all of it at once.

What I'm envisioning is that a struct like posn would get posn-with-x and posn-with-y, that would take a posn and a new x or y value and handle all the boilerplate.

In other words, to promote a student stu to the next grade, you'd just do (student-with-grade stu (+ 1 (student-grade stu))).

Unfortunately, I think I found out where define-struct is defined, but there's a ton of stuff in there, and I can't find the place where the constructors, selectors, and predicate are actually generated. I guess it's possible because they're actually generated by something like define-record-type, but I kind of got lost in the details.

Perhaps a workaround is to base the language on ISL, then set the parameter abbreviate-cons-as-list to #false. For example, this can be done by providing a module with (abbreviate-cons-as-list #f) and asking the students to require it.

The effect of setting this parameter to #false is this:

#lang htdp/isl

(cons "fst" (cons "snd" empty))
;; => (list "fst" "snd")

(require mzlib/pconvert)
(abbreviate-cons-as-list #false)

(cons "fst" (cons "snd" empty))
;; => (cons "fst" (cons "snd" '()))

You have two requests, of which I consider the second one quite reasonable in the abstract because I have had it on my mind for a decade :expressionless:

Concretely:

  1. Shriram and I have argued about naming values (local defines) in BSL or BSL+ time and again. He also firmly embraces the idea (though in detail, his request differs from yours). Why do I disagree? -- I consider BSL as a vehicle to teach both algebraic ideas and programming ideas (and in my mind they coincide). The goal is to have students break tasks into smaller functions, one per task, and to learn that function composition works.
    For reasons I don't get, students at this stage are always tempted to write very large functions that do everything in one fell swoop instead of thinking about the pieces of a task. -- More concisely: show me a place where local is desirable, and I show you a way to leverage basic pre-algebra knowledge.

  2. While I consider a full lens library per se as overkill, I agree that the overhead of changing something inside of a struct tree is too complex. But, just like for (1), I think bringing across that composition works might be a better experience here.

If your students are taking programming in high school to become software engineers, the above paragraphs point in the wrong direction. If they take it to learn how to solve problems in a visceral manner (unlike the normal paper-and-pencil math), my explanations are on target (I think).