Racket 如何申请打字/拍子?
在Racket 如何申请打字/拍子?,racket,typed-racket,Racket,Typed Racket,在typed/racket中,我有一个类似[(?procedure?p)(apply p xv*)]的案例 它将导致错误: Type Checker: Function has no cases in: (apply p xv*) 因此,我编写了一个测试用例来检测原因: #lang typed/racket (: test-match-apply-0 (-> (-> Any * Any) (Listof Any) Any)) (define test-match-apply-0
typed/racket
中,我有一个类似[(?procedure?p)(apply p xv*)]的案例
它将导致错误:
Type Checker: Function has no cases in: (apply p xv*)
因此,我编写了一个测试用例来检测原因:
#lang typed/racket
(: test-match-apply-0 (-> (-> Any * Any) (Listof Any) Any))
(define test-match-apply-0
(lambda (x args)
(match x
[(? procedure? p) (apply p args)])))
;; Type Checker: Function has no cases in: (apply p args)
(test-match-apply-0 + (list 1 2 3)) ;; not ok
(apply + (list 2 4)) ;; ok
(: test-match-apply-1 (-> (-> (Listof Any) Any) (Listof Any) Any))
(define test-match-apply-1
(lambda (x args)
(match x
[(? procedure? p) (apply p args)])))
(test-match-apply-1 + (list 1 2 3)) ;; not ok
;; For int is it right
(: test-match-apply-2 (-> (-> (Listof Any) Any) (Listof Number) Number))
(define test-match-apply-2
(lambda (x args)
(match x
[(? procedure? p) (apply p args)])))
(test-match-apply-2 + (list 1 2 3)) ;; not ok
(: test-match-apply-3 (-> (-> Number * Number) (Listof Number) Number))
(define test-match-apply-3
(lambda (x args)
(match x
[(? procedure? p) (apply p args)])))
(test-match-apply-3 + (list 1 2 3)) ;; it is ok
我打印+
本身:
> (:print-type +)
(case->
(-> Zero)
(-> Number Number)
(-> Zero Zero Zero)
(-> Number Zero Number)
(-> Zero Number Number)
(-> Positive-Byte Positive-Byte Positive-Index)
(-> Byte Byte Index)
(-> Positive-Byte Positive-Byte Positive-Byte Positive-Index)
(-> Byte Byte Byte Index)
(-> Positive-Index Index Positive-Fixnum)
(-> Index Positive-Index Positive-Fixnum)
(-> Positive-Index Index Index Positive-Fixnum)
(-> Index Positive-Index Index Positive-Fixnum)
(-> Index Index Positive-Index Positive-Fixnum)
(->* (Index Index) (Index) Nonnegative-Fixnum)
.....
回到我的原始需求,我如何才能在打字/拍子中使其成为可能?因为在这种情况下,我无法检测到p
的类型。类似于类型apply
类型化Racket无法应用该过程的原因是,除了它是一个过程这一事实之外,它对该过程一无所知。例如,它可能不接受任何参数,在这种情况下,apply
将导致运行时错误。它可能采用不同类型的参数,甚至可能具有必需的关键字参数。TR仅仅从过程?
谓词中不知道这一点,因此它不允许您调用这样的值
这是一个棘手的问题,因为没有一个谓词允许您检查函数的足够详细信息,以确保安全应用。您基本上有两种选择:
约束输入的类型,以便过程?
将其限制为特定的功能类型。可以通过使输入成为特定类型的并集来实现这一点。例如,此类型检查:
(: constrained ((U String Number (String * -> String)) -> String))
(define (constrained x)
(match x
[(? string?) x]
[(? number?) (number->string x)]
[(? procedure?) (apply x '("a" "b" "c"))]))
尽管这里的类型是联合类型,但由于只有一种情况下过程?
谓词为true,TR可以将该类型限制为适当适用的值
函数本身的类型可能非常奇特,TR仍然可以理解它。例如,它仍然适用于多态类型:
(: poly-constrained (All [a] (U String Number (a * -> String)) (Listof a) -> String))
(define (poly-constrained x lst)
(match x
[(? string?) x]
[(? number?) (number->string x)]
[(? procedure?) (apply x lst)]))
或者,您可以使用cast
。这将允许您告诉TR执行一个动态检查,确保某个值与特定类型匹配
(: unconstrained (Any -> String))
(define (unconstrained x)
(match x
[(? string?) x]
[(? number?) (number->string x)]
[(? procedure?) (apply (cast x (String * -> String)) '("a" "b" "c"))]))
但是,请注意,这有点大危险!使用cast
有几个陷阱:
- 该检查为单个值生成类型化/非类型化边界,实际上是类型化模块和非类型化模块之间相同的边界。这意味着
cast
会生成一个契约,在运行时进行检查,与静态类型不同,它需要时间,如果在紧密循环中使用,会显著降低性能
- 由于
cast
动态执行检查,您将失去类型化球拍的主要优点之一:静态类型安全。例如,如果有人提供了一个与给定类型不匹配的过程,就会发生运行时错误,这正是Typed Racket设计用来防止的
如果可能的话,您可能希望使用第一种方法,这样就不会影响类型安全性,但是在谓词不够好的情况下,您可以使用cast
。在选择它之前,请注意它的缺点。谢谢。起源问题来自这里,我试图用typed/racket
编写一个解释器。因此,特定函数类型
可以在某些特定函数中成功。但不能用于翻译。我说得对吗?@jiamo在我看来,s-interp
的类型太宽了,不是应该是(ExprS ParseEnv->ExprS)
?还是我遗漏了什么?(无论如何,这是一个比你在这里问的更广泛的问题。)@jiamo这是一个非常古老的问题,在评论中讨论通常没有帮助。如果你有一个新问题,可以随意问,但要确保你有一个新问题。