[plt-scheme] Local function definition

From: Joe Marshall (jrm at ccs.neu.edu)
Date: Tue Jan 13 09:43:35 EST 2004

"Dor Kleiman" <dor at ntr.co.il> writes:

>   For list-related administrative tasks:
>   http://list.cs.brown.edu/mailman/listinfo/plt-scheme
>
> I think so too; for instance, the following example (or anything with
> write-read) is quite much simpler with co-mingling:
> ; with co-mingling
> (define (connect-to-server)
>   (display "Server address: ")
>   (define ip (read-line))
>   (display "Port: ")
>   (define port (read))
>   (tcp-connect ip port))

Ouch!  Internal definitions are equivalent to a LETREC.  Rather than
defining some internal variables this way, consider what happens when
you define internal functions:

(define (even-or-odd? x)

  (define (even? x)
    (or (zero? x)
        (odd (- x 1))))

  (define (odd? x)
    (not (even? x)))

  (if (even? x)
      'even
      'odd))

Both the functions EVEN? and ODD? have to share the same lexical scope
or otherwise they won't be able to call each other.  So in your example:

(define (connect-to-server)
   (display "Server address: ")
   (define ip (read-line))        <<<< this variable
   (display "Port: ")
   (define port (read))           <<<< and this variable
   (tcp-connect ip port))

Both variables IP and PORT share the same scope, but it sure doesn't
look that way.

What would you think this does?

(define foo (lambda () 22))

(define (bar)
  (define helper (lambda () (foo)))
  (display "Helper: ")
  (display (helper))
  (define foo (lambda () 11))
  (display "Foo:  ")
  (display (foo)))

> ; without co-mingling
> ; example 1
> (define (connect-to-server-1)
>   (display "Server address: ")
>   (let ([ip (read-line)])
>     (display "Port: ")
>     (let ([port (read)])
>       (tcp-connect ip port))))

This version is *much* clearer.  It is obvious that IP is bound before
PORT, and furthermore that the computation of IP has no need to use
PORT. 

> ; example 2
> (define (prompt p f)
>   ; displays the prompt p and runs f (e.g. read or read-line)
>   (display p)
>   (f))
> (define (connect-to-server-2)
>   (define ip (prompt "Server address: " read-line))
>   (define port (prompt "Port: " read))
>   (tcp-connect ip port))

Use LET*:

 (define (connect-to-server-2)
   (let* ((ip (prompt "Server address: " read-line))
          (port (prompt "Port: " read)))
     (tcp-connect ip port)))

> ; example 3
> (define (connect-to-server-3)
>   (define ip (begin (display "Server address: ")
>                     (read-line)))
>   (define port (begin (display "Port: ")
>                       (read)))
>   (tcp-connect ip port))

(define (connect-to-server-3)
  (let* ((ip (begin (display "Server address: ") (read-line)))
         (port (begin (display "Port: ") (read-line))))
    (tcp-connect ip port)))



Posted on the users mailing list.