
the biggest problem I’m having with Racket so far is matching and fixing the damn parentheses…

There’s an ‘automatic parentheses’ mode in DrRacket that might help: preferences -> Editing tab -> General Editing subtab -> ‘Enable automatic parentheses’ . This will automatically add a balanced closing parens every time you type a new open one. You can also select a chunk of text in the editor and press an open parens and it will automatically surround the selection with the matching closing parens. Unfortunately it doesn’t help with deleting or removing extraneous parens if you end up with too many.

@sergej I’m happy to help hook you up with emacs and paredit. You can’t have unbalanced parens that way.

Thanks, I’ve actually found parinfer earlier, just didn’t want to switch to Emacs yet

@zenspider and anyone else who was interested in coffee - Two Creek Coffee House is open 8–3:30 and is really close to class

@chris-lowen you are a gentleman and a saint

there’s a girl here who delivered food. Guess she’s waiting on @mflatt to sign off

So Redex pattern-matching behaves like the Barendregt convention is maintained?

I love that phrasing. "[Makes sense] is not the same as [right]", but it can be more useful sometimes! :+1:

Would this be a correct #:binding-forms
annotation for the progs being added? (prog (defun (x_1 x_2) e_1 #:refers-to x_1) ... e_2 #:refers-to x_1 ...)

Oh, wait, mutually recursive.

I think you can just have a binding form for defun?

The defuns need to be mutually recursive, and the main body of the program has to be able to refer to all of the defuns

When were those requirements specified?

Lecture notes for this morning’s session

:+1:

This is at least superficially accepted by Redex: (prog (defun (x_1 x_2) e_1 #:refers-to x_1 ...) ... e_2 #:refers-to x_1 ...)

(added moar ellipses)

I think your function body needs to refer to the argument too.

good point!

I did #:refers-to x_1 ... x_2
, but I’m not sure of the rightward extent of #:refers-to

If you want a list in a refers-to clause I think you need to use the shadow
form, as in #:refers-to (shadow x_1 ... x_2)

Yeah, I added that and I’m running into some problems with substitute

Re: lecture — There’s a whole host of reasons why there wouldn’t be a name clash here, I think

A language-agnostic answer is that binding forms make sure this doesn’t happen. Even though we don’t have a binding form for defun
, I believe we still can’t collide with any lambda
bindings, because lambda
itself has a binding form.

A language-specific answer is that we just can’t face that situation in this language, because we can’t reduce under lambdas to begin with.

@zeeshanlakhani has joined the channel

quite a bunch of us from the Seattle area :slightly_smiling_face:

For those interested, here’s a binding specification for a PCF-like language that seems to do the right thing #lang racket
(require redex)
(define-language PCF
(p ::= (program (d ...) e))
(d ::= (defun (f x) e))
(e ::=
(lambda (x) e)
(e e)
(e + e)
natural
x)
(f x ::= variable-not-otherwise-mentioned)
#:binding-forms
(lambda (x) e #:refers-to x)
(defun (f x) e #:refers-to x) #:exports f
(program (d ...) #:refers-to (shadow d ...) e_2 #:refers-to (shadow d ...)))
(define-term t1
(program
(defun (f x) (g (1 + x)))
(defun (g x) (f x))
(f (g (y)))))
(default-language PCF)
(term (substitute t1 g w))
(term (substitute t1 x w))

(For those of you I talked to about this earlier, dan is smart and figured out how to do this with out that magic undocumented #:...bind
thing.)

That’s not far from what I had, except defun
and program
are separated and there’s an #:exports
clause

What are the material differences between that and: (prog
(defun (x_1 x_2) e_1 #:refers-to (shadow x_1 ... x_2)) ...
e_2 #:refers-to (shadow x_1 ...))
?

(other than getting weird errors from substitute
in the latter)

@twisol what errors are you getting with that?it seems like it works for me

(term (substitute (prog (defun (f x) (f x)) (f f)) x x))
. . second: contract violation
expected: list?
given: 'f«0»

my grammar is slightly different from yours though

lemme snippet it


Oops, I forgot to undo some experimental changes I did after I saw yours


Dinner tonight is 6:00pm at Porcupine Pub & Grille https://goo.gl/maps/hHemMtjTGoz

Doing the JS-like semantics (like ({"11": "foo"})[11]
) is fun! :smile: Spoilers in thread below

I added a show
metafunction that takes numbers, strings, and booleans to their string representations, and allowed the key parameter to @
to be any of those things. Then I added a (where s_key (show k))
clause and pattern-matched on s_key
in the record.

@twisol to follow up on the binding-forms issue from earlier, I think that’s a bug in redex’s binding-forms and I filed an issue https://github.com/racket/redex/issues/118

@dan ooh, cool. Thanks!

Does it toString functions the way JavaScript does?

That is, function x () { return 5 }
x.toString() // => function x() { return 5 }

No, I didn’t implement show
for functions.

JavaScript does :slightly_smiling_face:

I only wanted a proof of concept that I could reasonably match non-string keys to string elements in a record. You can expand this by adding more things to show
.

I was just thinking about how bonkers JavaScript is. Didn’t mean to imply you missed something, just wondered how closely you tried to replicate!

Oh yeah, JS is so bonkers I tried not to do everything it does. I discussed the possibility with my seat neighbor, actually

You could use the static distance transformation from yesterday to convert lambdas to a normal form, then recurse on that structure to produce a canonical string for that function

It might be fun to do. It’s just way more work than I really wanted in order to get the behavior I needed.

@dan Does the binding form you posted earlier allow the bodies of defun
s to call other defun
s? So you get mutual recursion?

@twisol I thought it did, but substitute is still not doing the right thing

@twisol I’ve edited the program too many times to keep it straight, but this version should have the correct mutually recursive binding structure


@fbie has joined the channel

Semi-spoilery observations about the semantics of RacketSchool/Functions3
under this thread. (Warning: it’s practically essay-length…)

Is it fair to say that #lang RacketSchool/Functions3
is characterized by each function having a single “return address” register? That would mean that when a function calls itself, it forgets where to go when it itself returns, so it always returns to the point where it was called.
I think this might actually be testable! Compare the following functions:
(defun (f x)
(if (zero? x)
(++ 4 5)
(++ 4 (f x))))
(defun (g x)
(if (zero? x)
(++ 4 5)
(g (+ x -1))))
(defun (p x)
(if (zero? (+ x -50))
(++ 1 1)
(+ x 1)))
(defun (h x)
(if (zero? x)
0
(p (h (+ x -1)))))
If I call (f 4)
, the function never hits a base case, and so never returns. If it did, we would observe a ’stuck state. This is a bog-standard infinite loop in any language.
If I call (g 4)
, the function does hit a base case, and it gets ’stuck there. This demonstrates that recursive calls behave as expected: everything is normal up to this point.
If I call (h 4)
, the function eventually gets stuck! However, notice that the only way for it to get stuck is for the return value of h
to eventually become 50. However, the function returns 0 at the base case, and since we passed 4, we should have no more than four recursive calls. But p
is applied 50 times! This demonstrates that functions store their return address at a fixed location, not on the stack.

Oh yeah, and I give a halting program that distinguishes all three languages.

I think it was conjectured today that there was no such halting program for Functions3
? :slightly_smiling_face: (To be fair, Dr. Felleisen specifically mentioned exceptions as an.. exception.. and that’s exactly what this program rests on.)

4
0
'stuck