I've been practicing some with Typed Racket Scheme (this is my first month or so using Scheme), and I'm trying to rewrite the ZipWith function using types, and it's proving far more difficult that I thought.
Here is the untyped ZipWith I made and am trying to convert, very simple:
(define (zipwith fn . lists)
(apply map fn lists))
Here is my attempt at the typed version. I tried looking at the types for map
and apply
to try to figure it out some, but I haven't had any luck with it so far:
(: zip-with (All (c a b ...) (-> (-> a b ... b c) (Listof b) ... b (Listof c))))
(define (zip-with fn . lists)
(apply (inst map c a b ... b) fn lists))
The Dr Racket REPL I'm using gives me this error:
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: (-> a b ... b c) (List (Listof b) ... b) *
in: (apply (inst map c a b ... b) fn lists)
I see it complains about the apply
function, but are my expected types correct otherwise? I could use some advice on how the completely translate my untyped version.
Ideally, I'd like the typed version to behave as closely to the untyped as possible, so I can do something like this (an example output using the untyped version):
> (zipwith list '(1 2 3) '(4 5 6) '(7 8 9))
'((1 4 7) (2 5 8) (3 6 9))
Edit: I did manage a version like Haskell's, just copying the type signature as-is essentially. It is:
(: zip-with2 (All (a b c) (-> (-> a b c) (Listof a) (Listof b) (Listof c))))
(define (zip-with2 fn list1 list2)
(map fn list1 list2))
Although it's trickier to call than I would like (I had to use inst
on the functions I tried, cons
and list
).
zip-with
in Racket/Scheme is justmap
, and indeed, your implementation just forwards all of its arguments tomap
. Therefore, the type signature will be identical tomap
. – Alexis Kingzipwith
should be identical tomap
, since it's taking the same exact arguments. Addingapply
to the mix made this fact harder to see at first. – user1017523