【问题标题】:Function Definitions After Expressions in SchemeScheme中表达式后的函数定义
【发布时间】:2016-05-21 03:44:31
【问题描述】:

我知道我无法在表达式inside 中定义一个函数,但是在同一嵌套函数中定义一个表达式after 时出现错误。我将 R5RS 与 DrScheme 一起使用。

例如,这会抛出一个错误,'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)))

【问题讨论】:

  • 实际上,你可以在表达式中定义一个函数,只是不能使用define语法,它只能在某些上下文中使用,而是使用let,例如:(+ 2 (let ((square (lambda(x) (* x x)))) (square 4)))
  • 这个问题的重点是它 not 在表达式中。使用 lambda 语法会出现相同的错误。有几个很好的答案可以解释这里发生了什么。

标签: scheme


【解决方案1】:

在 R5RS 中,您只能在相当特定的地方使用define:特别是您可以(仅)在具有<body> 的表单的开头使用它。这在 5.2.2 中描述。这尤其意味着内部defines 永远不会出现在任何其他表达式之后,即使在<body> 中也是如此。

Native Racket(或您使用#lang racket 获得的任何正确名称)在这方面要灵活得多:您尝试做的事情(除了单臂if)在球拍。

【讨论】:

    【解决方案2】:

    可以在另一个定义中使用define。但是,有些方案不允许您在没有 else 部分的情况下拥有 if。这对我有用:

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

    您是否尝试过在开始时做出定义?也许这可能是您的口译员的问题。

    【讨论】:

    • R5RS 和 R7RS 都只指定内部定义可以出现在所有表达式之间 (see the relevant section in R5RS here)。我认为在任何地方都允许它们不符合规范,但我认为 Racket 的实现会尝试快速失败并尽可能最小化地解释规范。
    • 这显然超出了 R5RS 规范。你有顶层,在lambda 和派生形式的开头,你可能有本地定义。这既不是而且显然不是合规的方案代码。就像具有比规范更多绑定的实现一样,如果它碰巧在特定实现中工作是可以的,因为它不会破坏 Scheme 代码,但是这样做会使实现特定于锁定而不是标准符合代码。
    • 实际上我确实提到了我正在使用的解释器,所以@AlexisKing 是正确的。
    • 是的,@Sylwester,我认为这或多或少正是我所说的,尽管措辞更清楚一些。 :)
    【解决方案3】:

    define 在过程主体内(包括所有作为过程语法糖的形式,例如 letlet*letrec)仅在其他表达式之前是合法的,而在第一个表达式和它之后是不合法的不能是最后一种形式。

    您的示例没有说明为什么要在定义之前使用表达式的真正原因。除了将所有define 移到开头之外,您没有其他方法可以得到任何东西。例如。

    (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)))
    

    如果代码没有死。例如。这是尾部表达式,您可以使用let 来制作新的正文:

    (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)))))
    

    我认为也许我们需要一个示例,您认为有必要在表达式之后有定义,我们很乐意展示如何安排它。

    【讨论】:

    • 我基本上是在尝试处理来自 SICP 的数值练习中的一些边缘情况,我知道这不是解决问题的优雅方法,但很好奇为什么它无论如何都不起作用。显然在某些版本的 Scheme 中确实如此,只是不是我正在使用的。
    • @Sophia R5RS 是一个非常简短的规范,其中包含许多未定义的区域。 Racket 的#!r5rs 是一个不允许许多未定义行为的实现,因此如果您可以让您的代码在其中工作,那么它很可能也可以在其他实现中工作。
    猜你喜欢
    • 1970-01-01
    • 2013-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-14
    • 2023-03-25
    • 2021-05-25
    相关资源
    最近更新 更多