问题描述
我正在为将任意数量的列表压缩在一起的函数的语法苦苦挣扎.我目前有:
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:
域:(-> 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) '())
域:(-> 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函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!