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