1
votes

I understand I can't define a function inside an expression, but I'm getting errors defining one after an expression within the same nested function. I'm using R5RS with DrScheme.

For example, this throws an error, 'define: not allowed in an expression context':

(define (cube x)
  (if (= x 0) 0) ;just for example, no reason to do this
  (define (square x) (* x x))
  (* x (square x)))
3
Actually, you can define a function inside an expression, simply not with the define syntax, which can be used only in certain contexts, but with let, for instance: (+ 2 (let ((square (lambda(x) (* x x)))) (square 4))) - Renzo
The point of this question is that it's not inside of an expression. You get the same error with lambda syntax. There are a couple good answers that explain what's going on here. - Sophia Gold

3 Answers

4
votes

In R5RS you can only use define in rather specific places: in particular you can use it at the beginning (only) of forms which have a <body>. This is described in 5.2.2. That means in particular that internal defines can never occur after any other expression, even in a <body>.

Native Racket (or whatever the right name is for what you get with#lang racket) is much more flexible in this regard: what you are trying to do would (apart from the single-armed if) be legal in Racket.

1
votes

You can use define inside another definition. Some Schemes won't allow you to have an if without the else part, though. This works for me:

(define (cube x)
  (if (= x 0) 0 1) ; just for example, no reason to do this
  (define (square x) (* x x))
  (* x (square x)))

Have you tried making the definition at the beginning? maybe that could be a problem with your interpreter.

1
votes

define inside a procedure body (that includes all forms that are syntactic sugar for procedures, like let, let*, and letrec) are only legal before other expressions and never after the first expression and it can not be the last form.

Your example shows no real reason for why you would want to have an expression before definitions. There is no way you can get anything more than moving all define up to the beginning. eg.

(define (cube x)
  ;; define moved to top
  (define (square x) (* x x))
  ;; dead code moved under define and added missing alternative
  (if (= x 0) 0 'undefined) 
  (* x (square x)))

If the code isn't dead. eg. it's the tail expression you can use let to make a new body:

(define (cube x)
  (if (= x 0) 
      0
      (let ()
        ;; this is top level in the let
        (define (square x) (* x x))
        ;; required expression
        (* x (square x)))))

I think perhaps we would need an example where you think it would be warranted to have the define after the expression and we'll be happy to show how to scheme it up.