如何申请打字/球拍?

时间:2016-05-31 15:51:37

标签: 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
  (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)
 .....

回到我的原始需求,如何在[(? procedure? p ) (apply p xv*)]中使typed/racket成为可能?因为在这种情况下我无法检测p的类型。像type-apply这样的东西?

1 个答案:

答案 0 :(得分:4)

Typed Racket不能apply该程序的原因是因为除了它是一个程序之外它对它一无所知。它可能不会采用任何参数,例如,apply会导致运行时错误。它可能需要不同的参数,或者甚至可能需要关键字参数。 TR只是从成功的procedure?谓词中知道这一点,所以它不允许你调用这样的值。

这很棘手,因为没有谓词可以让您检查有关该函数的足够详细信息,以便安全应用。你基本上有两个选择:

  1. 约束输入的类型,以便procedure?将其限制为特定的函数类型。您可以通过使输入成为特定类型的并集来完成此操作。例如,这个类型检查:

    (: constrained ((U String Number (String * -> String)) -> String))
    (define (constrained x)
      (match x
        [(? string?) x]
        [(? number?) (number->string x)]
        [(? procedure?) (apply x '("a" "b" "c"))]))
    

    尽管这里的类型是联合类型,但由于procedure?谓词只有一种可能的情况,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)]))
    
  2. 或者,您可以使用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的一个主要好处:静态类型安全。例如,如果某人提供了与给定类型不匹配的过程,则会发生运行时错误,这正是Typed Racket旨在防止的类型。

  3. 如果可能,您可能希望使用第一种方法,以免损害类型安全性,但在谓词不够好的情况下,可以使用cast。在选择它之前,请注意缺点。