假设我想将以下无类型代码转换为键入的球拍。这些函数的灵感来自SICP,它们展示了如何完全根据函数构建数据结构。
(define (make-pair x y)
(lambda (c)
(cond
((= c 1) x)
((= c 2) y)
(error "error in input, should be 1 or 2"))))
(define (first p) (p 1))
(define (second p) (p 2))
要将其直接转换为键入的球拍,make-pair
函数的返回值似乎为(: make-pair (All (A B) (-> A B (-> Number (U A B)))))
。在此之后,first
的类型应为(: first (All (A B) (-> (-> Number (U A B)) A)))
。但是,在实现该函数时,我们现在无法直接调用(p 1)
,因为我们需要进行某种类型的输入,以确保first
仅返回类型A
。将first
的返回类型更改为(U A B)
可以正常工作,但是发生输入的负担会发生在用户而不是API中。那么在这种情况下我们如何在first
中使用事件类型(即,如何使用类型变量A
的谓词),以便我们可以安全地只返回该对的第一个组件?
更新
我尝试了一种与上述不同的方法,并要求将A
和B
的谓词作为make-pair
函数的参数提供。以下是代码:
#lang typed/racket
(define-type FuncPair (All (A B) (List (-> Number (U A B)) (-> A Boolean) (-> B Boolean))))
(: make-pair (All (A B) (-> A B (-> A Boolean) (-> B Boolean) (FuncPair A B))))
(define (make-pair x y x-pred y-pred)
(list
(lambda ([c : Number])
(cond
((= c 1) x)
((= c 2) y)
(else (error "Wrong input!"))))
x-pred
y-pred))
(: first (All (A B) (-> (FuncPair A B) Any)))
(define (first p)
(let ([pair-fn (car p)]
[fn-pred (cadr p)])
(let ([f-value (pair-fn 1)])
(if (fn-pred f-value)
f-value
(error "Cannot get first value in pair")))))
但是,检查(fn-pred f-value)
条件失败,错误为expected: A
given: (U A B) in: f-value
答案 0 :(得分:2)
从问题开头的无类型代码来看,似乎一对A和B是给出1
的函数,给出回A,给定2
,给出回B.表达此类函数的方法是使用case->
类型:
#lang typed/racket
(define-type (Pairof A B)
(case-> [1 -> A] [2 -> B]))
只需添加类型注释,即可以与原始无类型代码相同的方式定义访问者:
(: first : (All (A B) [(Pairof A B) -> A]))
(define (first p) (p 1))
(: second : (All (A B) [(Pairof A B) -> B]))
(define (second p) (p (ann 2 : 2)))
构造函数的类型应为:
(: make-pair : (All (A B) [A B -> (Pairof A B)]))
但是构造函数并没有完全正常工作。有一点是错误的是你的else
条款缺少else
部分。修复,为您提供:
(: make-pair : (All (A B) [A B -> (Pairof A B)]))
(define (make-pair x y)
(lambda (c)
(cond
[(= c 1) x]
[(= c 2) y]
[else (error "error in input, should be 1 or 2")])))
这几乎是正确的,如果打出的球拍太棒了,那就是。键入的球拍专门针对发生的输入处理equal?
,但它对=
执行的操作不同。将=
更改为equal?
会将其修复。
(: make-pair : (All (A B) [A B -> (Pairof A B)]))
(define (make-pair x y)
(lambda (c)
(cond
[(equal? c 1) x]
[(equal? c 2) y]
[else (error "error in input, should be 1 or 2")])))
理想情况下,事件类型应该与=
一起使用,但是像(= 2 2.0)
之类的事情返回true这一事实可能会使实现更难以实现更少。