我有一个函数,有点像assoc
,搜索列表中的符号并返回#f
或列表中的位置。
此函数的返回类型应为#f
和Natural
,(U #f Natural)
的联合。
但是当我想将该值用作数字时,它总是会输入不匹配,因为该值不仅仅是自然值,而且实际上是一个联合。
如何将Natural值拉出并避免类型不匹配错误?
答案 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
,因此可以这样使用。
如果你实际做想要在类型不匹配时抛出错误,你可以使用assert
或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
类型。
答案 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
将会是天生的。