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这是一个非常古老的问题,在评论中讨论通常没有帮助。如果你有一个新问题,可以随意问,但要确保你有一个新问题。