【问题标题】:How to define type predicates in Scheme如何在 Scheme 中定义类型谓词
【发布时间】:2025-12-18 16:00:02
【问题描述】:

“普通”函数通常只定义在给定类型的对象域上,但某些函数,例如 Scheme 类型谓词 list?procedure?,是为任何类型的参数定义的,甚至可以是适用于自己。所以例如(list? procedure?) 的计算结果为 #f(procedure? procedure?) 的计算结果为 #t。我试图弄清楚如何编写这种完全定义的函数,但一直无法找到讨论这个问题的来源。

例如,假设我们使用以下构造函数和选择器实现Structure and Interpretation of Computer Programs 的练习 2.4 中描述的对数据类型:

    (define (cons x y)
      (lambda (m) (m x y)))

    (define (car z)
      (z (lambda (p q) p)))

    (define (cdr z)
      (z (lambda (p q) q)))

然后我将如何定义一个谓词pair?,它为使用cons 构造的任何东西返回#t,而对于不是使用#f 构造的任何东西都返回#f?更一般地说,list?procedure? 这样的类型谓词是如何实现的?

【问题讨论】:

  • 你为什么要关心这对是如何构建的?如果是一对,那么无论如何都是一对。您可以将pair? 定义为一个不为空的列表,并且其cdr 不为空,但cdr 上的递归为#f。我很确定 list? 谓词需要是一个内置函数,因为它太基础了。
  • @d11wtq (define (list? x) (and (pair? x) (or (null? (cdr x)) (list? (cdr x))))) 检查参数对象是否是一个有限的正确列表。 pair? 只检查它是否是一个 cons 单元数据对象。 (let ((a (list 1))) (set-cdr! a a) (pair? (cdr a))) 必须能够返回 #t

标签: types scheme racket predicate


【解决方案1】:

这很容易。重新定义你的过程,让第一个参数是你正在创建的对象的类型:

(define +type-pair+ 'pair)
(define +type-number+ 'number)

(define (cons a d)
  (lambda (m) (m +type-pair+ a d)))

(define (type x)
  (x (lambda (t . rest) t)))

(define (pair? c)
  (eq? (type c) +type-pair+))

(define (car c)
  (if (pair? c)
      (c (lambda (t a d) a))
  (error "Argument is not pair!")))

(define (cdr c)
  (if (pair? c)
      (c (lambda (t a d) d))
  (error "Argument is not pair!")))

(define (number? c)
   (if (type c) +type-number+))

您可以使用它来定义您的语言中的所有内容,甚至是程序,但所有程序都必须支持使用 (type x) 为其指定类型,并且所有使用某些内容的程序必须确保类型正确。将对实现为闭包可能是最慢的方法,所以这只是 SICP 思想实验,让您了解闭包是什么。 Arc 对所有数据类型都使用标签,但将数据保留为数据。你应该看看 Arc,看看标记是如何成为一种方法的。

【讨论】:

  • 第二行有错别字。
【解决方案2】:

顺便说一下,在 Racket 中,使用 struct 制作的结构谓词已经为您完成了这项工作,因此您不必手动实现它。

每个专业级方案都通过结构或记录提供类似的功能。请参阅SRFI-9,它描述了许多其他 Scheme 实现已经为您做的事情。

【讨论】:

  • 谢谢,但我真的对如何“手动”进行操作很感兴趣,只是为了了解本机提供的功能的“底层”机制。
【解决方案3】:

你不能,用你展示的代码。程序是不透明的。

作为一种可能性,您必须更改构造函数/访问器以使用 标记 列表。

(define *church-pair-tag* (list '*church-pair-tag*))

(define (cons x y)
   (cons *church-pair-tag* (lambda(m) (m x y))))

(define (church-pair? x)
   (and (pair? x) 
        (eq? *church-pair-tag* (car x))
        (procedure? (cdr x))))

....

但这显然不是万无一失的。

谓词pair?procedure? 是内置的,可能是通过某种底层魔法实现的。 list? 可以用pair?、null?、carcdr 来实现。

【讨论】:

    最近更新 更多