如何在Scheme中定义类型谓词

EB *_*udd 5 scheme types predicate racket

"普通"函数通常仅在给定类型的对象域上定义,但某些函数(如Scheme类型谓词list?procedure?)是为任何类型的参数定义的,甚至可以应用于它们自身.因此,例如(list? procedure?)评估#f(procedure? procedure?)评估#t.我试图找出如何编写这种完全定义的函数,但未能找到讨论这个的源.

例如,假设我们使用以下构造函数和选择器实现了计算机程序结构和解释的练习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)))
Run Code Online (Sandbox Code Playgroud)

那么我如何定义一个谓词pair?,该谓词返回#t任何使用构造的东西cons,以及#f任何不构造的东西?更一般地,怎么都类型谓词喜欢list?procedure?实施?

Syl*_*ter 4

那很容易。重新定义您的过程,使第一个参数成为您正在创建的对象的类型:

(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+))
Run Code Online (Sandbox Code Playgroud)

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