问题描述
Typed Racket 是否提供了类型安全的 list-ref
函数?
如果您尝试访问超出范围的索引,list-ref
函数似乎会抛出错误:
> (require typed/racket)
> (list-ref '(1 2 3) 100)
; list-ref: index too large for list
; index: 100
; in: '(1 2 3)
list-ref
在给定其类型的情况下返回错误是有道理的:
> list-ref
- : (All (a) (-> (listof a) Integer a))
我想一个类型安全的版本会有如下类型:
(: list-ref (All (a) (-> (listof a) Integer (Option a)))
如果 Typed Racket 的某个地方提供了这个类型安全的 list-ref
函数,我将如何找到它?
如果这个类型安全的 list-ref
函数不存在,那为什么不存在呢?看来这个功能应该很有用。
解决方法
据我所知,它不存在。
您提议的 (All (a) (-> (Listof a) Integer (Option a)))
的一个问题是 (Option a)
只是 (U #f a)
。也就是说,您必须用 #f
表示“无”。但是,如果您有一个 (Listof Boolean)
,并且 list-ref*
(您的 list-ref
变体)返回 #f
,您如何判断是因为索引超出范围,还是因为元素确实是 #f
?
解决这个问题的一种可能方法是用盒子之类的东西包装“一些”变体,并相应地调整类型。例如,
(: list-ref* (All (a) (-> (Listof a) Integer (Option (Boxof a)))))
(define (list-ref* xs i)
(with-handlers ([exn:fail? (λ (_) #f)])
(box (list-ref xs i))))
请注意,包装会影响性能,这可能解释了为什么它不包含在库中。