是否可以写出类似C++的东西
template <typename... T> std::string dup(int n, std::string s, T... tail) {
std::string result;
for (int i = 0; i < n; ++i) {
result += s;
}
if constexpr (sizeof...(tail) == 0) {
return result;
} else {
return result + dup(tail...);
}
}
std::cout << dup(1, std::string("abc"), 2, std::string("xyz"), 3, std::string("a")) << std::endl; // abcxyzxyzaaa
我尝试在TypedRacket中编写以下函数
#lang typed/racket
(: repeat-string (-> Integer String String))
(define (repeat-string n str)
(apply string-append (build-list n (λ (_) str))))
(: dup (All (T ...) (-> Integer String T ... T String)))
(define (dup n s . tail)
(define result (repeat-string n s))
(cond [(empty? tail) result]
[else (string-append result (apply dup tail))])
)
但是我有类型检查错误:
Type Checker: Bad arguments to function in 'apply': Domain: Integer String T ... T Arguments: (List T ... T) in: (apply dup tail)
老实说,我不明白为什么争论是
(List T ... T)
而不是(T ... T)
。而且,该函数是正确的,非类型化的 Racket 会产生正确的结果
->*
和 #:rest-star
关键字指定函数的类型:
#lang typed/racket
(: repeat-string : Integer String -> String)
(define (repeat-string n s)
(string-append* (make-list n s)))
(: dup (->* (Integer String) #:rest-star (Integer String) String))
(define (dup n s . rest)
(if (null? rest)
(repeat-string n s)
(string-append (repeat-string n s) (apply dup rest))))
(dup 1 "abc" 2 "xyz" 3 "a") ; "abcxyzxyzaaa"
Rec
和 List*
来创建类型签名:
(: dup2 : (Rec IntStrRepeated (U Null (List* Integer String IntStrRepeated))) -> String)
(define (dup2 pairs)
(if (null? pairs)
""
(string-append (repeat-string (car pairs) (cadr pairs)) (dup2 (cddr pairs)))))
(dup2 '(1 "abc" 2 "xyz" 3 "a")) ; "abcxyzxyzaaa"