如何在Typed Racket中实现类似C++可变模板参数的dup函数?
Typed Racket中可变参数dup函数的类型错误问题解决
问题原因
Typed Racket的静态类型系统比无类型Racket严格得多:
- 无类型Racket是动态类型,对
apply的参数结构不做检查,只要运行时参数合法就能正常执行。 - Typed Racket里,接受可变参数的函数(比如你定义的
dup)要求传入的是展开的单个参数序列,而你递归时传入的tail是一个列表类型(List T ... T),两者类型不匹配。此外,你原来的类型声明没有约束剩余参数必须是成对的Integer + String,类型系统无法推断出tail的结构符合dup的参数要求,因此抛出错误。
解决方法
你可以通过拆分函数职责,分别处理可变参数输入和列表递归逻辑来避免类型错误,示例代码如下:
#lang typed/racket ; 处理列表形式的参数,递归拼接结果 (: dup-list : (List Integer String ...) String) (define (dup-list args) (match args ['() ""] [(cons n (cons s rest)) ; 将字符串s重复n次后拼接,再递归处理剩余参数 (string-append (string-append* (make-list n s)) (dup-list rest))])) ; 对外暴露的可变参数接口,将可变参数转为列表传入dup-list (: dup : Integer String * String) (define (dup . args) (dup-list args))
代码说明:
dup-list专门处理列表类型的参数,类型声明(List Integer String ...)明确约束了输入必须是成对的整数和字符串序列,递归时直接传列表,类型完全匹配。dup作为对外的可变参数接口,接受任意多组成对的Integer + String参数,内部将参数转为列表交给dup-list处理,既满足了可变参数的使用需求,又通过类型声明明确了参数结构。
如果你坚持要在递归中使用apply,可以通过类型断言(cast)告诉类型系统tail的结构符合要求,但这种方式不够安全,不推荐:
#lang typed/racket (: dup : Integer String * String) (define (dup . args) (match args ['() ""] [(cons n (cons s rest)) (string-append (string-append* (make-list n s)) (apply dup (cast rest (List Integer String ...))))]))
内容的提问来源于stack exchange,提问作者Q Qere
相关产品推荐
相关产品推荐

