如何在typed/racket申请?
How to apply in 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)
.....
回到我的原始需求,我怎样才能在typed/racket
中实现[(? procedure? p ) (apply p xv*)]
?因为在这种情况下我无法检测到 p
的类型。像 type-apply
这样的东西?
Typed Racket 不能 apply
该过程的原因是除了它是一个过程这一事实之外,它对它一无所知。它可能不接受任何参数,例如,在这种情况下 apply
会导致运行时错误。它可能需要不同的 kind 参数,或者它甚至可能需要关键字参数。 TR 仅从成功的 procedure?
谓词中不知道任何这些,因此它不允许您调用这样的值。
这很棘手,因为没有谓词可以让您检查有关函数的足够详细信息,从而可以安全地应用它。你基本上有两个选择:
限制输入的类型,以便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)]))
或者,您可以使用 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
:
有几个陷阱
检查为单个值生成一个 typed/untyped 边界,实际上是类型化模块和非类型化模块之间的相同类型的边界。这意味着 cast
生成一个在运行时检查的合同,与静态类型不同,它需要时间并且如果在紧密循环中使用会显着降低性能。
由于 cast
动态执行检查,您失去了 Typed Racket 的主要优点之一:静态类型安全。例如,如果某人提供的过程与给定类型不匹配,则会发生 运行时错误,这正是 Typed Racket 旨在防止的事情。
如果可能,您可能希望使用第一种方法,以免损害类型安全,但在谓词不够好的情况下,您可以使用cast
。在选择它之前,请注意它的缺点。
在 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)
.....
回到我的原始需求,我怎样才能在typed/racket
中实现[(? procedure? p ) (apply p xv*)]
?因为在这种情况下我无法检测到 p
的类型。像 type-apply
这样的东西?
Typed Racket 不能 apply
该过程的原因是除了它是一个过程这一事实之外,它对它一无所知。它可能不接受任何参数,例如,在这种情况下 apply
会导致运行时错误。它可能需要不同的 kind 参数,或者它甚至可能需要关键字参数。 TR 仅从成功的 procedure?
谓词中不知道任何这些,因此它不允许您调用这样的值。
这很棘手,因为没有谓词可以让您检查有关函数的足够详细信息,从而可以安全地应用它。你基本上有两个选择:
限制输入的类型,以便
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)]))
或者,您可以使用
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
:检查为单个值生成一个 typed/untyped 边界,实际上是类型化模块和非类型化模块之间的相同类型的边界。这意味着
cast
生成一个在运行时检查的合同,与静态类型不同,它需要时间并且如果在紧密循环中使用会显着降低性能。由于
cast
动态执行检查,您失去了 Typed Racket 的主要优点之一:静态类型安全。例如,如果某人提供的过程与给定类型不匹配,则会发生 运行时错误,这正是 Typed Racket 旨在防止的事情。
如果可能,您可能希望使用第一种方法,以免损害类型安全,但在谓词不够好的情况下,您可以使用cast
。在选择它之前,请注意它的缺点。