Elegant Method of binding a function variable

I'm trying to bring myself up to speed on LISP/Scheme and am having one of those days when my brain cell has migrated to another dimension.

I have the following code(given in Scheme):

(begin
(define x 5)
(define (incx n) (+ x n))
(print (incx 2))
(define x 4)
(print (incx 2))
)

The first print will return 7, the second 6.

What I want is for the x in incx to be permanently bound to the first definition (5), so that I get 7 in both calls to incs.

I can do it by assigning x to another name (_x, say) and using that, but I would like a more elegant method of doing it - particularly one that doesn't involve creating an alternative name.

All ideas gratefully received.

Stuart

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

An answer

One method is:

(define incx
  (let ((x x))
    (lambda (n) (+ x n))))

BTW, this kind of homework question is not really appropriate for the forums here.

Elegance and Programmer Laziness

Thanks for your reply, Frank.

That was the approach I tried first (it didn't work on the first LISPish tool I used (newLisp) - incx was still binding to the next definition; worked in DRScheme).

However, what I was really after was some construct that automatically binds any non-parametric variables to the nearest preceding in-scope lexical definition. I could write a function, whatever, to analyse the code and fill in the gaps, but I was hoping to avoid that kind of translation.

As for homework, I suspect I formally gave that up before you started :-) [not that I ever did very much anyway]. I've just been recapping about 8 different languages in one day (Algol 68, Lisp, Prolog, Maple, ML, Haskell, C??, J & Python) and have gone into syntactic shock.

However, I take your point and will look for a more suitable forum.

Stuart

Another INTJ, eh? I wonder if there if something about INTJers that attracts them to Maths ...

Block macro

Here's something I wrote a while ago as an example for someone on #scheme:

(define-syntax block
  (syntax-rules (def)
    ((block)
     #f)
    ((block (def var val) body ...)
     ((lambda (var) (block body ...)) val))
    ((block body)
     body)
    ((block body1 body2 ...)
     (begin body1 (block body2 ...)))))



The idea is that any DEF inside a BLOCK implicitly introduces a new scope that lasts until the end of the innermost containing BLOCK.

Let's try it with your example:

(block
  (def x 5)
  (def incx (lambda (n) (+ x n)))
  (print (incx 2)) ; prints 7
  (def x 4)
  (print (incx 2))) ; prints 7

Block Macro

Interesting. Thanks. I'd been looking for an elegant way of doing that.

The other option I'd considered was analysing each definition and creating a let for each variable not in the function parameter list.

Sadly, it won't work on my DR Scheme - it doesn't seem to recognize define-syntax.

I still have this nagging feeling that there ought to be some more direct method of solving the problem.

Stuart

Dr Scheme

Sadly, it won't work on my DR Scheme - it doesn't seem to recognize define-syntax.

Sure it does. You probably have the language level set to one of the beginner levels. Set it to e.g. "Pretty Big" and it'll work fine (I wrote and tested it with Dr Scheme).

Nope :-) It didn't work on *m

Nope :-) It didn't work on *my* DRScheme (in Full Scheme mode). However, I did have the somewhat antediluvian 103; hence, I suppose, the help reference to R4 Scheme.

I've just downloaded 209 and it works fine. Thank you.

Hmm. I notice all kinds of extensions to Scheme ... ah well, once more unto the breach - or would fray be a better analogy, "When truth kills truth, O devilish-holy fray!"?

Stuart

Not actually valid Scheme

The above code is not actually valid R5RS Scheme, which requires that in a <body> all the <definition>s precede the <expression>s, precisely to prevent playing tricks like this. If you want controlled scope, use LET or LET*.

Oh. I'm an INTP.

Valid Scheme?

I've just been flicking through the MIT Scheme Reference and it seems to indicate that define-syntax can be used in a lambda body. It notes the restriction you pointed out (even though it only refers to R4)

Stuart

Maybe it's just being INT* makes people value programming.

Pointer to INT?

Maybe it's just being INT* makes people value programming.

Would that make interest in programming a pointer to INT? ;-)

Validity

I'm not sure which code the "above code" refers to, but the example in the original post is valid if it appears at top level, since per R5RS, a sequence within a begin at top level is equivalent to the same sequence at top level.

The block macro also looks valid to me, since it defines something quite similar to a LET*, and doesn't emit any definitions, only lexical bindings via lambda. In fact, since it emits code with a lexically nested structure, it could alternatively emit definitions at the beginning of the lambda body in its second case, but that would be a bit perverse. :)

Your intent

I'm a bit unclear on your intent.

First, why is this wrapped in a begin?

Second, is the purpose of (define x 4) to rebind x, or introduce a new x?

Since the only existing user of x is incx, and you want it to use the original value, presumably you want a new x. So, as John Cowan points out, you could use let to introduce a new scope with a new x. You could also just use a new name, after all if the new binding of x has no relationship to any previous use of x, why use the same name?

Gary

My intent

The intent was to play around with the Mathcad 12/13 XML files.

Mathcad (www.mathcad.com), for those not familiar with it, is a pseudo-freeform application for evaluating mathematical expressions, it's main feature being that it uses mathematical notation wherever possible - you input an integral by selecting an integral operator from a toolbar/keyboard-shortcut/menu, rather than typing Int(...) as in what seems like the majority of mathematical programming languages. The result, on your screen, is a standard mathematical integral sign with placeholders to type in the integrand and independent variable.

Mathcad saves files in its own XML format file, the structure of which defines a mathematical expression in prefix form. It looks awfully close to LISP, so I was just idly speculating about writing a translator.

However, Mathcad's mode of execution is slightly different from the norm. Definition of a 'variable' is done by k:=5; I can define a function by f(x):=sin(x)*x. The equivalent Mathcad 'program' to the Scheme fragment given above is:

x:=5
incx(n):= x + n
incx(2)=7 {'=' evaluates incx and displays the result}
x:=4
incx(2)=7

Mathcad evaluates strictly (left-to-right) top-to-bottom, and the definition of incx is bound to the first definition of x. Any subsequent changes to x are not visible to function defintion - they effectively redefine x rather than 'update' it.

Hence the reason for my question. I wanted to avoid explicitly using let and avoid the work involved in creating a function to analyze a function definition and auto-create the lets.

Stuart