为什么 `filter` 使用高阶出现类型?

Why does `filter` work with higher-order occurrence typing?

在 Racket 的主页上,他们展示了这个例子:

#lang typed/racket
;; Using higher-order occurrence typing
(define-type SrN (U String Number))
(: tog ((Listof SrN) -> String))
(define (tog l)
  (apply string-append (filter string? l)))
(tog (list 5 "hello " 1/2 "world" (sqrt -1)))

我知道在出现类型中,像 (if (string? v) ...) 这样的表达式会将 v 标记为在真正的分支中具有 String 类型。这是因为 string? 的类型有一个过滤器:

> string?
- : (Any -> Boolean : String)
#<procedure:string?>

因此,对于 "higher-order occurrence typing" 与 filter 函数一起使用,我希望 filter 的类型表明谓词类型的过滤器传播到结果类型.但是当我在 REPL 中检查 filter 的类型时,这并没有显示:

> filter
- : (All (a b) (case-> ((a -> Any) (Listof a) -> (Listof b)) ((a -> Any) (Listof a) -> (Listof a))))
#<procedure:filter>

但这不可能是filter的真实类型,因为b没有约束!我期待

(All (a b) (a -> Any : b) (Listof a) -> (Listof b))

tldr:为什么 filter 在其 return 类型中出现了一个不受约束的类型变量?

编辑:我正在使用 Racket v6.0

Typed Racket Reference中说:

In some cases, asymmetric type information is useful in filters. For example, the filter function’s first argument is specified with only a positive filter. Example:

> filter
- : (All (a b)
      (case->
       (-> (-> a Any : #:+ b) (Listof a) (Listof b))
       (-> (-> a Any) (Listof a) (Listof a))))
#<procedure:filter>

The use of #:+ indicates that when the function applied to a variable evaluates to a true value, the given type can be assumed for the variable. However, the type-checker gains no information in branches in which the result is #f.

换句话说,如果你有下面的例子:

> (filter string? '(symbol 1 2 3 "string"))
- : (Listof String)
'("string")

只有当 string? returns true 时,系统才会说列表 '(symbol 1 2 3 "string") 的元素是 String 类型。仅在这种情况下传播过滤器谓词的类型。