You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Racket中以normal order实现自定义if(不切换lazy语言)

在标准Racket中实现遵循正常序的new-if

方法一:使用宏(最贴近正常序行为)

Racket的宏在代码展开阶段处理逻辑,不会提前求值参数,完美契合正常序「先展开、再按需求值」的特性。将new-if定义为宏即可解决问题:

#lang racket
(define (p) (p))

(define-syntax new-if
  (syntax-rules ()
    [(new-if test-expr then-expr else-expr)
     (cond (test-expr then-expr)
           (else else-expr))]))

执行(new-if (= 2 2) 5 (p))时,宏会先展开为(cond ((= 2 2) 5) (else (p)))。由于Racket的cond是特殊形式,仅会在测试条件为真时求值对应分支,因此(p)永远不会被执行,直接返回5。

方法二:手动延迟求值(Thunk)

若不想使用宏,可将需要延迟的分支包装为无参数函数(即Thunk),在需要时再调用。修改new-if的定义,让它接收Thunk作为分支参数:

#lang racket
(define (p) (p))

(define (new-if test-expr then-thunk else-thunk)
  (cond (test-expr (then-thunk))
        (else (else-thunk))))

调用时需将分支表达式包装为lambda:

(new-if (= 2 2) (lambda () 5) (lambda () (p)))

此时传递的是lambda对象,不会提前求值(p);当测试条件为真时,仅会调用(then-thunk)得到5,else-thunk永远不会被执行。

原代码问题分析

原代码中的new-if是普通函数,而Racket作为应用序语言,会在调用函数前先求值所有参数。执行(new-if (= 2 2) 5 (p))时,会先求值(p),而(p)是递归调用自身,直接陷入死循环。

Racket内置的if是特殊形式,遵循正常序求值规则:先测试条件,仅在条件为真时求值then分支、为假时求值else分支,不会提前求值所有分支。上述两种实现正是模拟了这种行为。

内容的提问来源于stack exchange,提问作者Mitchell Xu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 20:20:08