使用多态联合类型进行输入

时间:2016-08-31 10:27:40

标签: racket typed-racket

假设我想将以下无类型代码转换为键入的球拍。这些函数的灵感来自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的谓词),以便我们可以安全地只返回该对的第一个组件?

更新

我尝试了一种与上述不同的方法,并要求将AB的谓词作为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

1 个答案:

答案 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这一事实可能会使实现更难以实现更少。