Typed Racket的类型检查器不允许我通过

编程语言 2026-07-11

我有一个函数 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,但这基本上会因为同样的原因而导致类型检查失败:参数必须是列表,而你的函数可能返回非列表值。即便这不是问题,它也会得到与原版本不同的结果——把字符串展平成一个字符串列表,而不是字符串列表的列表。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章