TypedRacket 中的函数输入

问题描述 投票:0回答:1

是否可以写出类似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 会产生正确的结果

racket typed-racket
1个回答
0
投票

以适当的类型安全执行此操作的关键是使用

->*
#: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"
© www.soinside.com 2019 - 2024. All rights reserved.