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))
Which causes the following error when evaluated:
Error: struct:exn:fail:syntax /Applications/Racket v6.6/collects/racket/private/kw.rkt:929:25: Type Checker: Bad arguments to function in `apply':
Domains: (-> a b ... b c) (Listof a) (Listof b) ... b
(-> a c) (Pairof a (Listof a))
Arguments: (-> Any * (Listof Any)) (Listof (Listof Any)) *
in: (#%app apply map (#%expression list) lsts)
Since these evaluate okay:
(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"))
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) '())
Error: struct:exn:fail:syntax /Applications/Racket v6.6/collects/racket/private/kw.rkt:929:25: Type Checker: Bad arguments to function in `apply':
Domains: (-> a b ... b c) (Listof a) (Listof b) ... b
(-> a c) (Pairof a (Listof a))
Arguments: (-> Any * (Listof Any)) Null *
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).
The function
map
needs to take at least one list as an argument. Consider what would happen if you calledzip
with zero arguments. Then you would be callingmap
with zero lists, which isn't allowed. So, you have to restrict yourzip
function to take one or more arguments. You can do that by specifying an argument before the rest argument like this:One more thing: This would be better if it were polymorphic.
Notice that the domain still needs to be
(Listof A) (Listof A) *
and not just(Listof A) *
.Update: Even more polymorphism
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 typeHowever, if the body were
(apply map list lst lsts)
, thelist
function would need the typeHowever,
list
used as a function value only has the type(All (a) (-> a * (Listof a)))
. Instead we can define a new functionlistd
, which behaves exactly likelist
, but with the new typeUsing this, the dots-polymorphic version of
zip
can be defined like this:Using it: