如何 "promise" 一个值将是某种类型

How to "promise" that a value will be a certain type

如果我在typed/racket中有这个功能:

(: random-if-empty (-> (U Image-Color "empty") Image-Color))
(define (random-if-empty s)
  (cond
    [(equal? s "empty") (random-color)]
    [else s]))

如果输入 returns 随机颜色是 "empty",否则它是 returns 输入,我如何阻止类型检查器说 s ( in [else s]) 可以是 Image-Color "empty" 而不是预期的 Image-Color?还是有更好的整体方法来做到这一点?我正在使用 typed/2htdp/image 库,这是 Image-Color 的来源。

您可以利用 occurrence typing 告诉类型检查器您的 s 在第二种情况下不能是字符串。

#lang typed/racket

(require typed/2htdp/image)

(define (random-color) : Image-Color
  (color 0 0 0)) ;; dummy

(: random-if-empty (-> (U Image-Color "empty") Image-Color))
(define (random-if-empty s)
  (cond
    [(string? s) (random-color)]
    [else s]))

为什么 string? 有效而不是 (equal? s "empty)"?我不知道,但我猜 Typed Racket 没那么聪明。

您也可以使用assertions

(: random-if-empty (-> (U Image-Color "empty") Image-Color))
(define (random-if-empty s)
  (cond
    [(equal? s "empty") (random-color)]
    [else (assert s string?)]))

如果您的类型真的很复杂,您可能不得不求助于 casting,它们的编写方式就像断言一样。但是我已经按照优先顺序给出了这些解决方案。铸造应该是最后的手段。

equal? 谓词可以通知类型系统变量是或不是某个值,但是,这仅适用于某些类型的某些值。它适用于一些简单类型(布尔值、符号、空列表、void 以及 01),但不适用于大多数其他数据类型,包括字符串。

(这可能与字符串可变有关,我不确定。)

解决这个问题的方法是以不同的方式为 "empty" 字符串创建您自己的谓词。 Typed racket 提供了 make-predicate 形式,它可以将一些简单的 "flat" 类型转换为谓词。你可以这样使用它:

(define my-empty-pred? (make-predicate "empty"))

这个新谓词将能够更直接地使用 occurrence typing 来告诉类型系统如果 (my-empty-pred? x) returns 为真,那么 x 的类型为 "empty",如果它 returns false 那么 x 的类型不应该包含 "empty"。所以你可以在你的例子中使用它,比如:

(: random-if-empty (-> (U Image-Color "empty") Image-Color))
(define (random-if-empty s)
  (cond
    [(my-empty-pred? s) (random-color)]
    [else s]))