ZipWith in Typed Racket,带有多个列表

时间:2016-06-18 06:02:09

标签: types racket typed-racket

我一直在练习使用Typed Racket Scheme(这是我使用Scheme的第一个月左右),而我正在尝试使用类型重写ZipWith函数,而且我认为它要困难得多。

这是我制作的无类型ZipWith,我试图转换,非常简单:

(define (zipwith fn . lists)
  (apply map fn lists))

这是我对打字版本的尝试。我试着查看mapapply的类型,试图找出一些,但到目前为止我还没有运气:

(: 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))

尽管调用比我想要的要复杂(我必须对我尝试过的函数使用instconslist)。

1 个答案:

答案 0 :(得分:2)

正如Alexis King已经指出的那样,zip-with在球拍中确实是map,其类型签名应该是相同的。地图的类型是

> (:print-type map)
(All (c a b ...)
  (case->
   (-> (-> a c) (Pairof a (Listof a)) (Pairof c (Listof c)))
   (-> (-> a b ... b c) (Listof a) (Listof b) ... b (Listof c))))

仅查看多列表案例,就是这样:

(All (c a b ...)
  (-> (-> a b ... b c) (Listof a) (Listof b) ... b (Listof c)))

但你写的类型是:

(All (c a b ...)
  (-> (-> a b ... b c) (Listof b) ... b (Listof c)))

fn函数将a作为第一个参数,但在您编写的类型中没有对应的(Listof a)参数。

即使是map / zip-with的广义多参数版本也需要至少一个列表才能使用,这就是(Listof a)必需的原因。这也是为什么而不是

的原因
(define (zip-with fn . lists)
  (apply map fn lists))

你需要

(define (zip-with fn list1 . lists)
  (apply map fn list1 lists))

通过这两项更改,您的代码可以正常运行:

#lang typed/racket

(: zip-with : (All (c a b ...) (-> (-> a b ... b c) (Listof a) (Listof b) ... b (Listof c))))
(define (zip-with fn list1 . lists)
  (apply (inst map c a b ... b) fn list1 lists))

它甚至可以在没有inst形式的情况下运行:

(: zip-with : (All (c a b ...) (-> (-> a b ... b c) (Listof a) (Listof b) ... b (Listof c))))
(define (zip-with fn list1 . lists)
  (apply map fn list1 lists))

因为zip-withmap无论如何都是一样的:

(: zip-with : (All (c a b ...) (-> (-> a b ... b c) (Listof a) (Listof b) ... b (Listof c))))
(define zip-with map)

即使它们具有相同的值,但这样做的好处是类型看起来稍微简单,只有多列表情况。