如何 "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 以及 0
和 1
),但不适用于大多数其他数据类型,包括字符串。
(这可能与字符串可变有关,我不确定。)
解决这个问题的方法是以不同的方式为 "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]))
如果我在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 以及 0
和 1
),但不适用于大多数其他数据类型,包括字符串。
(这可能与字符串可变有关,我不确定。)
解决这个问题的方法是以不同的方式为 "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]))