Typed Racket的类型检查器不允许我通过
我有一个函数 string-split*,它接受 s(RecurListofString,一种递归数据类型,下面定义)和 lsep(一个分隔符字符串的列表),并输出RecurListofString,即一个已被拆分的结果。
这个函数在 racket 中运作良好,racket 是该语言的无类型版本。但在 typed/racket 中,类型检查器一直在抱怨 cons,这是为什么?ChatGPT一点也没帮上忙。
#lang typed/racket
(define-type RecurListofString (U String (Listof RecurListofString)))
(: string-split* (-> RecurListofString
(Listof String)
RecurListofString))
(define (string-split* s lsep)
(cond
[(null? s) '()]
[(null? lsep) s]
[(string? s) (string-split*
(string-split s (car lsep))
(cdr lsep))]
[(list? s) (cons
(string-split* (car s) lsep)
(string-split* (cdr s) lsep))]))
错误:
Type Checker: Polymorphic function `cons' could not be applied to arguments:
Types: a (Listof a) -> (Listof a)
a b -> (Pairof a b)
Arguments: RecurListofString RecurListofString
Expected result: RecurListofString
in: (cons (string-split* (car s) lsep) (string-split* (cdr s) lsep))
解决方案
请记住,Listof 使用的“规范列表”被定义为要么是 '(),空列表,或者是一条或多条对构成的链,其最后的cdr为空列表。
你的函数被规定返回要么一个(规范的)列表,要么一个字符串。
(cons
(string-split* (car s) lsep)
(string-split* (cdr s) lsep))
does not meet that specification, because it can return a pair whose cdr is a string (Even though that will never actually happen, the type checker doesn't do the sort of analysis needed to prove it). You have to tell Typed Racket that (string-split* (cdr s) lsep) is expected to return a list, and thus the type checker will deduce that that cons will also return a list and so will accept it:
(cons (string-split* (car s) lsep)
(assert (string-split* (cdr s) lsep) list?))
Barmar建议在注释中使用 append,但这基本上会因为同样的原因而导致类型检查失败:参数必须是列表,而你的函数可能返回非列表值。即便这不是问题,它也会得到与原版本不同的结果——把字符串展平成一个字符串列表,而不是字符串列表的列表。