Types ZipWith输入球拍,具有多个列表

Types ZipWith输入球拍,具有多个列表,types,racket,typed-racket,Types,Racket,Typed Racket,我一直在练习使用类型化的Racket Scheme(这是我使用Scheme的第一个月左右),我正在尝试使用类型重写ZipWith函数,事实证明这比我想象的要困难得多 这是我制作并试图转换的非类型ZipWith,非常简单: (define (zipwith fn . lists) (apply map fn lists)) 这是我对打字版本的尝试。我试着查看map和apply的类型,试图找出其中一些类型,但到目前为止我还没有找到任何运气: (: zip-with (All (c a b ..

我一直在练习使用类型化的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
函数,但我期望的类型是否正确?我可以就如何完全翻译我的非类型版本提供一些建议

理想情况下,我希望类型化版本的行为尽可能接近非类型化版本,因此我可以这样做(使用非类型化版本的示例输出):

编辑:我确实管理了一个类似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
)。

正如亚历克西斯·金(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
作为第一个参数,但在您编写的类型中没有相应的
(a的列表)
参数

即使是广义的多参数版本的
map
/
zip with
也至少需要一个列表,这就是为什么
(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 with
map
是一回事:

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

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

值得指出的是,Racket/Scheme中
zip with
只是
map
,实际上,您的实现只是将其所有参数转发到
map
。因此,类型签名将与
map
@AlexisKing相同谢谢,我以前没有看到过!您是对的,
zipwith
的签名应该与
map
相同,因为它使用相同的参数。在混音中添加
apply
,一开始就很难看出这个事实。太棒了!这为我澄清了很多事情。非常感谢。
(: zip-with : (All (c a b ...) (-> (-> a b ... b c) (Listof a) (Listof b) ... b (Listof c))))
(define zip-with map)