Scheme 有没有办法声明一个类型来表示TypedRacket中所有可调用的过程(任何可调用的过程)?

Scheme 有没有办法声明一个类型来表示TypedRacket中所有可调用的过程(任何可调用的过程)?,scheme,racket,typed-racket,Scheme,Racket,Typed Racket,我正在使用键入的Racket和Stick开发SICP的元循环评估器,并在事先准备原始程序时使用了符号和程序对象的cons列表。在这本书中,作者准备了如下的基本过程,然而,当我在类型化的Racket中模拟它并在其上定义访问器时,我根本无法提取过程或符号,因为我需要用一个我无法写下的类型显式实例化car或cdr,即列表中所有过程类型的并集。 所以我想,如果我可以声明一个表示所有可调用过程的类型(没有关键字args,但有rest args),我最终可以对下面的列表进行注释。我认真地在谷歌上搜索并尝试了

我正在使用键入的Racket和Stick开发SICP的元循环评估器,并在事先准备原始程序时使用了符号和程序对象的cons列表。在这本书中,作者准备了如下的基本过程,然而,当我在类型化的Racket中模拟它并在其上定义访问器时,我根本无法提取过程或符号,因为我需要用一个我无法写下的类型显式实例化car或cdr,即列表中所有过程类型的并集。 所以我想,如果我可以声明一个表示所有可调用过程的类型(没有关键字args,但有rest args),我最终可以对下面的列表进行注释。我认真地在谷歌上搜索并尝试了很多方法,但我没有想出好主意。有人能想出一个好办法来定义这样一个类型吗?甚至更好的是,谁能想出一个更好的主意来准备所有的原始程序呢

(define primitive-procedures
    (list (cons 'car car)
          (cons 'cdr cdr)
          (cons 'list list)
          ...))

问题在于试图将一组异构函数类型适配到同构列表类型/同构查找结果类型中

在注释中,您注意到您不能给出类型
基本过程:(All(ab)(Listof(Pairof Symbol(->a*b)))
因为声明的类型不同于实际列表中的每个过程。您可能尝试添加
All
,因为您试图容纳其中的所有异构类型。但是
Listof
类型,更重要的是,用于从列表中获取原语的
查找
函数,具有基本功能完全同质的类型。您必须使类型同质化,并处理列表中的类型

如果目标语言中的值与元循环解释器的主机相同,则此同构函数类型的最简单选择是
(>Any*Any)

然后使用
apply
可以使用
lookup基元
。然而,最复杂的部分是使用这种同质类型的
基元过程的定义

只是使用

(define primitive-procedures
  (list (cons 'car car)
        (cons 'cdr cdr)
        (cons 'list list)
        ...))
这还不够,并导致类型不匹配

  • 汽车
    不能用作
    (>Any*Any)
    。它可以用作
    (>(Pairof Any)Any)
  • cdr
    不能用作
    (>Any*Any)
    。它可以用作
    (>(Pairof Any)Any)
  • 列表
    可以用作
    (>Any*Any)
    。这很好
因此,我们必须以某种方式包装
car
cdr
,在将参数传递给
car
cdr
之前,使用函数检查参数数量并检查参数是否成对

(lambda [args : Any *]
  (match args
    [(list arg)
     (unless (pair? arg) (error 'car "wrong argument type"))
     (car arg)]
    [_
     (error 'car "wrong number of arguments")]))

现在这个lambda表达式可以用作<代码>(->任何**)< />代码,但是它是笨拙的。当你认为我们必须为每个已经不适合的原语做这件事时更糟:

(define primitive-procedures
  (list (cons 'car (lambda [args : Any *]
                     (match args
                       [(list arg)
                        (unless (pair? arg) (error 'car "wrong argument type"))
                        (car arg)]
                       [_
                        (error 'car "wrong number of arguments")])))
        (cons 'cdr (lambda [args : Any *]
                     (match args
                       [(list arg)
                        (unless (pair? arg) (error 'cdr "wrong argument type"))
                        (cdr arg)]
                       [_
                        (error 'cdr "wrong number of arguments")])))
        (cons 'list list)
        ...))
这段代码很难看,而且经常重复。我会定义一个名为
prim
的宏来为我执行此模式:

(require syntax/parse/define)

(define-simple-macro (prim (arg-pred ...) proc)
  #:with (arg-id ...) (generate-temporaries #'(arg-pred ...))
  (lambda [args : Any *]
    (match args
      [(list arg-id ...)
       (unless (arg-pred arg-id) (error 'proc "wrong argument type")) ...
       (proc arg-id ...)]
      [_
       (error 'proc "wrong number of arguments")])))
然后我们可以在
基本过程中使用它

(define primitive-procedures
  (list (cons 'car (prim (pair?) car))
        (cons 'cdr (prim (pair?) cdr))
        (cons 'list list)
        ...))

现在它最终被定义为同构类型
(Listof(Pairof Symbol(->Any*Any))

试着看看在类型化的racket中
apply的类型是什么。是的,我已经做了,结果有些无意义。apply的类型签名是(All(ab)(>a*b)(Listof a)b)和(->a*b)不适合我们的primitve过程的类型签名。例如,尽管我将基本过程的类型声明为(:primitive procedures:(All(ab)(Listof(Pairof)(Symbol(->a*b '))),类型检查器仍然声称,事先声明的类型与实际列表中的每个过程都不同。SICP是一本非常难学的教科书。为了能够执行书中的代码,最好在mit scheme中学习。SICP课程不处理类型。如果你非常初学者,你将无法执行iSICP需要很多年才能完成,即使是对于一个专业的计算机工程师来说也是如此。完成后,你可以像SICP一样学习其他教科书中的类型。放弃键入语言,用一种更简单的方式,用非键入的方式来做。@alinsoar谢谢你的建议。说实话,m的非键入版本etacircular evaluator在没有SICP模块的非类型化Racket中已经运行良好。这就是为什么我想要在类型化版本上工作。而且,在这篇文章之后,我想到了一个想法,当我初始化环境结构时,我可以将所有原始过程第一手放在环境中。也许这应该运行良好。谢谢。我N类型化方案您将永远无法运行像这样的组合器。当您达到用CPS编写程序的程度时,您将无法再使用任何类型化语言。
(define primitive-procedures
  (list (cons 'car (prim (pair?) car))
        (cons 'cdr (prim (pair?) cdr))
        (cons 'list list)
        ...))