从Typed Racket union中提取类型

时间:2015-04-07 19:03:19

标签: racket typed-racket

我有一个函数,有点像assoc,搜索列表中的符号并返回#f或列表中的位置。

此函数的返回类型应为#fNatural(U #f Natural)的联合。

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

如何将Natural值拉出并避免类型不匹配错误?

2 个答案:

答案 0 :(得分:5)

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。在第二种情况下,函数只是错误而不返回,因此类型仍然存在。

在大多数情况下,您不仅会在失败案例中出错,而且还会提供某种替代行为。这仍然允许您在主体内细化类型。

(define n : (Option Natural) #f)

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

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

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

(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类型。

答案 1 :(得分:2)

做这样的事情:

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

(define i (assoc ...))我们知道i的返回类型为assoc,即它是#f或自然。在cond条款[i <use-i-here>]中,<use-i-here>仅在i不是#f时才会被评估,因此类型检查器知道<use-i-here> i将会是天生的。