decent way of nested definition in scheme

≡放荡痞女 提交于 2019-12-10 18:53:53

问题


I want to define a constant foo using an auxiliary function, say, bar. And I want to hide bar inside the definition of foo, so I come with this code:

(define foo
  (define (bar n)
    (+ n n))
  (bar 1))

However, this definition causes syntax errors in many scheme implementations(mit-scheme, racket, guile, etc.).

I have three workarounds but none of them seems satisfactory:

(define foo1
  ((lambda ()
     (define (bar n)
       (+ n n))
     (bar 1))))

(define foo2
  (let ((bar (lambda (n) (+ n n))))
    (bar 1)))

(define (foo3)
  (define (bar n)
    (+ n n))
  (bar 1))

foo1 uses lambda to create an environment of writing auxiliary definitions and the parentheses seem somehow confusing.

foo2 uses let expression but I can no longer use the syntactic sugar (define (f n) ...) => (define f (lambda (n) ...))

foo3 requires less modification comparing with the original one, but every time I want this value, I have to call (foo3) and do the computation all over again.

My questions are:

  1. I think this kind of nested definition makes sense, but why it is considered a syntax error?
  2. is there any decent way to write the definition of foo?

回答1:


Answering your questions:

  1. define can only be used in certain ways, as mandated by the specification. What you want to do isn't covered by the specification, hence the error. As you know, define assigns a name to the value of an expression, it's just that you can't directly create internal definitions in its context.
  2. But there are other expressions that allow creating new bindings in this context. IMHO foo2 is the best option here, and it's idiomatic, too. And if bar were a recursive definition, you could use letrec.

But if loosing a bit of syntactic sugar bothers you (because of the way procedures are defined inside a let expression), then try using local, it'll work in Racket:

(define foo
  (local [(define (bar n) (+ n n))]
    (bar 1)))



回答2:


If I understand your question correctly, another idiomatic way to do this in Racket would be to use a module.

This module could be defined using a separate file:

;; foo.rkt
#lang racket
(define (bar n)
  (+ n n))
(define foo (bar 1))
(provide foo)

;; use-foo.rkt
#lang racket
(require "foo.rkt")
foo

Or via a module form within one file:

#lang racket
(module 'foo-mod racket
  (define (bar n)
    (+ n n))
  (define foo (bar 1))
  (provide foo))

(require 'foo-mod)
foo

Is this concise compared to your examples? Of course not. But in practice this sort of encapsulation usually works fine at a module granularity.

  • For instance a private helper like bar might be useful in defining multiple other functions or constants.

  • Often the file form is more convenient: If a helper like bar is not nested, but instead at the module top level for foo.rkt, it's easier to debug it in a REPL.

p.s. Racket provides a define-package form for compatibility with Chez Scheme, but it's not idiomatic in Racket; instead you'd use a submodule.




回答3:


Your original code has a syntax error because the required syntax for define of an identifier is

(define <identifier> <expression>)

but your syntax is

(define <identifier> <definition> <expression>)

You need some way to group the <definition> and the <expression>. What you are looking for is something that allows lexical definitions - in Scheme this is a syntactic form with a <body>. The syntactic forms for this are a lambda or any let (and variants) or a 'programmatic' begin.

But, this is easily done in Scheme w/o needing Racket extensions or extra, empty lexical environments or a <body> syntactic form. Just use what you considered 'unsatisfactory'

(define foo
  (let ((bar (lambda (x) (+ x x))))
    (bar 1)))

or even

(define foo
  ((lambda (x) (+ x x)) 1))

Too much sugar, even syntactic sugar, my have adverse health consequences...




回答4:


foo1 is also equivalent to the following:

(define foo1
  (let ()
    (define (bar n)
      (+ n n))
    (bar 1)))

Is that more acceptable-looking to you?



来源:https://stackoverflow.com/questions/20896471/decent-way-of-nested-definition-in-scheme

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!