从 Typed Racket 联合中提取类型

Extract a type from a Typed Racket union

我有一个功能,有点像 assoc,在列表中搜索一个符号,returns #f 或列表中的位置。

此函数的 return 类型应该是 #fNatural(U #f Natural).

的并集

但是当我想将该值用作数字时,它总是类型不匹配,因为该值不仅是一个自然值,而且实际上是一个联合。

如何提取 Natural 值并避免类型不匹配错误?

Typed Racket 有一项名为 Occurrence Typing 的功能,它允许您使用谓词和断言来过滤值的类型。基本思想是 string?empty?number? 等谓词可以根据程序的控制流 过滤 类型。

为了说明这一点,请看这个例子:

(: nat/#f->nat ((U Natural False) -> Natural))
(define (nat/#f->nat n)
  (if n n
      (error "Expected a number, given " n)))

这将进行类型检查,因为如果采用第一个分支,则 n 不能是 #f,因此它必须是 Natural。在第二种情况下,函数只是出错而不是 return,所以类型仍然成立。

在大多数情况下,您不会只是简单地在失败情况下出错,而是会提供某种替代行为。这仍然允许您在主体本身内细化类型。

(define n : (Option Natural) #f)

(cond
  [n
   ; do something with n as a number
   (+ n 1)]
  [else
   ; do something else
   (void)])

在第一个案例中,n的类型被细化为Natural,因此可以这样使用。

如果您实际上 只想在类型不匹配时抛出错误,则可以使用 assert or cast。前者实际上是一个派生概念,它基本上执行与上面第一个示例相同的检查。你这样使用它:

(assert n number?) ; now n is a number, and if it isn't, an error is thrown
(+ n 1)

cast 形式有点不同,因为它指定 types 而不是谓词。这意味着您可以像这样使用它:

(+ (cast n Natural) 1)

如果发现 n 实际上不是 Natural,这也会引发错误,否则,整个表达式变为 Natural.[=30= 类型]

做这样的事情:

(define i (assoc ...))
(cond
  [i    <use-i-here>]
  [else <raise-error>])

(define i (assoc ...)) 我们知道 i 具有 assoc 的 return 类型,即它是 #f 或自然数。在 cond 子句 [i <use-i-here>] 中,仅当 i 不是 #f 时才会评估 <use-i-here>,因此类型检查器知道 <use-i-here> i 将顺其自然。