Предположим, я хочу преобразовать следующий нетипизированный код в типизированную ракетку. Эти функции вдохновлены 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