如何在Scheme中定义类型谓词

时间:2012-08-05 21:19:15

标签: types scheme racket predicate

“普通”函数通常仅在给定类型的对象域上定义,但某些函数(如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?,该谓词#t为使用cons构建的任何内容返回#f,而list?用于任何不是?更一般地说,如何实现procedure?和{{1}}等类型谓词?

3 个答案:

答案 0 :(得分: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+))

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

答案 1 :(得分:3)

顺便说一下,在Racket中,使用struct进行的结构谓词已经为你工作了,所以你不必手动实现它。

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

答案 2 :(得分:1)

你不能,你已经显示的代码。程序是不透明的。

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

(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来实现。