带剩余参数的类型化球拍中的Zip函数 [英] Zip function in typed racket with rest arguments

查看:119
本文介绍了带剩余参数的类型化球拍中的Zip函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为将任意数量的列表压缩在一起的函数的语法苦苦挣扎.我目前有:

I'm struggling with the syntax for a function that zips together any number of lists. I currently have:

(define (zip . [lsts : (Listof Any) *]) (apply map (inst list Any) lsts))

(define (zip . [lsts : (Listof Any) *]) (apply map (inst list Any) lsts))

在评估时会导致以下错误:

Which causes the following error when evaluated:

错误:struct:exn:fail:syntax/Applications/Racket v6.6/collects/racket/private/kw.rkt:929:25:类型检查器:错误 在`apply'中起作用的参数:

Error: struct:exn:fail:syntax /Applications/Racket v6.6/collects/racket/private/kw.rkt:929:25: Type Checker: Bad arguments to function in `apply':

域:(-> a b ... b c)(Listof a) (清单b)... b

Domains: (-> a b ... b c) (Listof a) (Listof b) ... b

(-> a c)(Pairof a(Listof a))

(-> a c) (Pairof a (Listof a))

参数:(->任意*(Listof Any))(Listof(Listof Any))*

Arguments: (-> Any * (Listof Any)) (Listof (Listof Any)) *

在:(#%app套用地图(#%表达式列表)lsts)

in: (#%app apply map (#%expression list) lsts)

由于这些评估还可以:

(apply map (inst list Any) '(("asd" 1 2) ("cat" 3 4))) ;;(("asd" "cat") (1 3) (2 4))

(apply map (inst list Any) '(("asd" 1 2) ("cat" 3 4))) ;;(("asd" "cat") (1 3) (2 4))

(define (test . [lsts : (Listof Any) *]) lsts) (test '(1 2 3) '(2 3 "dogs")) ;;((1 2 3) (2 3 "dogs"))

(define (test . [lsts : (Listof Any) *]) lsts) (test '(1 2 3) '(2 3 "dogs")) ;;((1 2 3) (2 3 "dogs"))

我认为类型检查器抱怨apply每当不传入任何参数时都会失败,因为在尝试评估以下内容时会遇到类似的错误:

I think the type checker's complaining about apply failing whenever no arguments are passed in, since I get a similar error trying to evaluate the following:

(apply map (inst list Any) '())

错误:struct:exn:fail:syntax/Applications/Racket v6.6/collects/racket/private/kw.rkt:929:25:类型检查器:错误 在`apply'中起作用的参数:

Error: struct:exn:fail:syntax /Applications/Racket v6.6/collects/racket/private/kw.rkt:929:25: Type Checker: Bad arguments to function in `apply':

域:(-> a b ... b c)(Listof a) (清单b)... b

Domains: (-> a b ... b c) (Listof a) (Listof b) ... b

(-> a c)(Pairof a(Listof a))

(-> a c) (Pairof a (Listof a))

参数:(->任意*(列表的任意))空*

Arguments: (-> Any * (Listof Any)) Null *

in:(#%app apply map(#%expression list)(quote()))

in: (#%app apply map (#%expression list) (quote ()))

但是我不确定如何向函数指定它将至少使用一个参数(列表).

But I'm not sure how to specify to the function that it'll take at least one argument (list).

推荐答案

函数map需要至少包含一个列表作为参数.考虑一下如果您使用零参数调用zip会发生什么.然后,您将使用零个列表调用map,这是不允许的.因此,您必须限制您的zip函数接受一个或多个参数.您可以通过在其余参数之前指定一个参数来做到这一点,例如:

The function map needs to take at least one list as an argument. Consider what would happen if you called zip with zero arguments. Then you would be calling map with zero lists, which isn't allowed. So, you have to restrict your zip function to take one or more arguments. You can do that by specifying an argument before the rest argument like this:

#lang typed/racket

(define (zip [lst : (Listof Any)] . [lsts : (Listof Any) *])
  (apply map (inst list Any) lst lsts))

还有一件事:如果它是多态的,那会更好.

One more thing: This would be better if it were polymorphic.

#lang typed/racket

(: zip : (∀ (A) (-> (Listof A) (Listof A) * (Listof (Listof A)))))
(define (zip lst . lsts)
  (apply map (inst list A) lst lsts))

请注意,域仍然需要为(Listof A) (Listof A) *,而不仅仅是(Listof A) *.

Notice that the domain still needs to be (Listof A) (Listof A) * and not just (Listof A) *.

更新:更多的多态性

实际上有可能使这个多态性更好,因此,如果您给它精确的3个列表,它将产生一个恰好3个元素的列表.此版本的zip的类型为

It's actually possible to make the polymorphism on this even better, so that if you give it exactly 3 lists, it produces a list of exactly-3-element lists. This version of zip would have the type

(: zip : (∀ (A B ...)
            (-> (Listof A)         ; first input
                (Listof B) ... B   ; next n inputs, where n is the number of B type-arguments
                (Listof (List A B ... B)))))

但是,如果主体是(apply map list lst lsts),则list函数将需要类型

However, if the body were (apply map list lst lsts), the list function would need the type

(∀ (A B ...) (-> A B ... B (List A B ... B)))

但是,用作功能值的list仅具有类型(All (a) (-> a * (Listof a))).相反,我们可以定义一个新函数listd,其功能与list完全相同,但是具有新类型

However, list used as a function value only has the type (All (a) (-> a * (Listof a))). Instead we can define a new function listd, which behaves exactly like list, but with the new type

;; (listd x y z) = (list x y z)
;; but it's assigned a type that's more convenient for `zip`
(: listd : (∀ (A B ...) (-> A B ... B (List A B ... B))))
(define (listd a . bs)
  (cons a bs))

使用此,可以像这样定义zip的点多态版本:

Using this, the dots-polymorphic version of zip can be defined like this:

(: zip : (∀ (A B ...)
            (-> (Listof A)         ; first input
                (Listof B) ... B   ; next n inputs, where n is the number of B type-arguments
                (Listof (List A B ... B)))))
(define (zip lst . lsts)
  (apply map (inst listd A B ... B) lst lsts))

使用它:

> (zip (list 'a 'b 'c) (list 1 2 3) (list "do" "re" "mi"))
- : (Listof (List (U 'a 'b 'c) Positive-Byte String))
'((a 1 "do") (b 2 "re") (c 3 "mi"))

这篇关于带剩余参数的类型化球拍中的Zip函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆