【发布时间】:2016-10-20 00:19:33
【问题描述】:
我一直在使用 Typed Racket Scheme 进行一些练习(这是我使用 Scheme 的第一个月左右),我正在尝试使用类型重写 ZipWith 函数,结果证明它比我想象的要困难得多。
这是我制作并尝试转换的无类型 ZipWith,非常简单:
(define (zipwith fn . lists)
(apply map fn lists))
这是我对打字版本的尝试。我尝试查看 map 和 apply 的类型以试图弄清楚一些,但到目前为止我还没有运气:
(: 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))
我正在使用的 Dr Racket REPL 给了我这个错误:
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)
我看到它抱怨 apply 函数,但我预期的类型是否正确?我可以就如何完全翻译我的无类型版本提出一些建议。
理想情况下,我希望类型化版本的行为尽可能接近非类型化版本,因此我可以这样做(使用非类型化版本的示例输出):
> (zipwith list '(1 2 3) '(4 5 6) '(7 8 9))
'((1 4 7) (2 5 8) (3 6 9))
编辑:我确实管理过一个类似 Haskell 的版本,基本上只是按原样复制类型签名。它是:
(: 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))
虽然调用起来比我想的要复杂(我必须在我尝试过的函数上使用inst,cons 和list)。
【问题讨论】:
-
值得指出的是,Racket/Scheme 中的
zip-with只是map,实际上,您的实现只是将其所有参数转发给map。因此,类型签名将与map相同。 -
@AlexisKing 谢谢,我以前没见过!你是对的,
zipwith的签名应该与map相同,因为它采用相同的确切参数。将apply添加到混合中会使这个事实一开始更难看到。
标签: types racket typed-racket