Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Racket handle (define (f (x y)) body)?

I'm learning Racket, and wrote this definition:

(define y 2)
(define (f (x y))
  (print x)
  (print y))

When I evaluate (f 1), x is bound to 1, and y is bound to 2. This seems very strange to me. How is this expression being expanded? What does the interpreter do with this?

like image 962
kedebug Avatar asked Jan 10 '23 08:01

kedebug


2 Answers

It's an optional argument

The grammar for definitions in Racket is in the documentation.

3.14 Definitions: define, define-syntax, ...

(define id expr)
(define (head args) body ...+)

head  =       id
      |       (head args)

args  =       arg ...
      |       arg ... . rest-id

arg   =       arg-id
      |       [arg-id default-expr]
      |       keyword arg-id
      |       keyword [arg-id default-expr]

Most of my Lisping is in Common Lisp where square brackets aren't parentheses, so I initially misread the grammar. The part about [arg-id default-expr] means you can have an optional argument with a default value. So

(define (f (x y)) …)

defines f as a procedure that accepts 0 or 1 arguments. If the argument is not provided, then its default value is y. That's why this works when you have an earlier definition of y. This also means that you can call (f), and you should see the value of y printed:

enter image description here

This was pointed out to me on the Racket users mailing list by Robby Findler and Tony Garnock-Jones in the thread [racket] (define (f (x y)) body) when y has a previous definition.

It's not legal in R5RS

This isn't legal in R5RS Scheme. The definition for definitions is given in:

5.2 Definitions

Definitions are valid in some, but not all, contexts where expressions are allowed. They are valid only at the top level of a and at the beginning of a .

A definition should have one of the following forms:

(define <variable> <expression>)
(define (<variable> <formals>) <body>)

should be either a sequence of zero or more variables, or a sequence of one or more variables followed by a space-delimited period and another variable (as in a lambda expression). This form is equivalent to

(define <variable>
  (lambda (<formals>) <body>)).

(define (<variable> . <formal>) <body>)

should be a single variable. This form is equivalent to

(define <variable>
  (lambda <formal> <body>)).

Dr.Racket won't accept your definition in the R5RS language:

Dr.Racket Screenshot

like image 129
Joshua Taylor Avatar answered Jan 19 '23 13:01

Joshua Taylor


In Racket an argument can be defined as (argument-name default-value) (usually you'd use square brackets for this, but that's only a matter of style - the language itself does not care).

So (define (f (x y)) ...) defines a function f that takes one argument named x whose default value is y.

like image 28
sepp2k Avatar answered Jan 19 '23 13:01

sepp2k