类型化Racket:使用define type创建泛型类型

类型化Racket:使用define type创建泛型类型,racket,generic-programming,typed-racket,Racket,Generic Programming,Typed Racket,我正试着对打字技巧有一点了解,但我在让一个(公认的是构建的)实验起作用时遇到了一些困难 这就是我最初拥有的: #lang typed/racket (: generate-list (All (A) ((A -> A) (Integer -> A) Integer -> (Listof A)))) (define (generate-list function location-function num-items) (let: loop : (Listof

我正试着对打字技巧有一点了解,但我在让一个(公认的是构建的)实验起作用时遇到了一些困难

这就是我最初拥有的:

#lang typed/racket

(: generate-list
   (All (A)
   ((A -> A) (Integer -> A) Integer -> (Listof A))))

(define (generate-list function location-function num-items)
  (let: loop : (Listof A)
    ((count : Integer 0)
     (result : (Listof A) (list)))
    (if (>= count num-items)
        (reverse result)
        (loop (+ count 1)
              (cons (function (location-function count)) result)))))

; ---------------------------------
(: f (Number -> Number))
(define (f x) (* x x))

(: locf (Integer -> Number))
(define (locf x) x)
; ---------------------------------

(displayln (generate-list f locf 10))
其输出为:

(0 1 4 9 16 25 36 49 64 81)
这很好。然后我想我可以通过给函数和位置函数定义一个类型来更好地记录这一点:

#lang typed/racket

(define-type (ListGenFunction A) (A -> A))
(define-type (ListGenLocFunction A) (Integer -> A))

(: generate-list
   (All (A)
        (ListGenFunction ListGenLocFunction Integer -> (Listof A))))

(define (generate-list function location-function num-items)
  (let: loop : (Listof A)
    ((count : Integer 0)
     (result : (Listof A) (list)))
    (if (>= count num-items)
        (reverse result)
        (loop (+ count 1)
              (cons (function (location-function count)) result)))))

; ----------- Numbers! ------------
(: f ListGenFunction)
(define (f x) (* x x))

(: locf ListGenLocFunction)
(define (locf x) x)
; ---------------------------------

(displayln (generate-list f locf 10))
现在问题就从这里开始了(我真的希望一些有经验的敲诈勒索者现在不要太露骨了)。首先,类型检查器在我定义f的行上给了我一个错误。消息相当长,但基本上是:“类型检查器:在函数应用程序中没有匹配的函数域:类型:…在:(*x x)”中。我想我定义了一个类型,它有一个泛型类型a的参数,返回泛型类型a?(*x x)不起作用吗?或者是否需要“标记”类型?(例如,在类似C++的语言中,它是列表)

最重要的是:现在我的函数generate list的类型定义有一个返回类型“(Listof a)”。但是,声明的A与类型为ListGenFunction和ListGenLocFunction的参数所期望的A完全不同。但是,我有点想建立这种连接,这样使用该函数的任何人都可以确保他提供的函数的类型与返回列表项的类型匹配

如何正确地执行此操作

附言: 我不确定我是否在最后一段描述了我的意图,以便任何人都能理解。但是如果您使用一些类似于伪C++的通用代码,我想得到以下结果:

list<T> generate-list(LGF<T> f, LGLF<T> locf, int count) { ... }
列表生成列表(LGF,LGLF locf,int count){…}

所以所有的T都是完全相同的。

这里有两个问题,它们都源于相同的混淆。您使用的是泛型类型,
listgenefunction
,而没有告诉键入的Racket(或程序的读者)您使用的是哪种特定类型

例如,
f
不是一个任意的
listgenefunction
,它是一个专门处理数字的
listgenefunction
。所以你应该写:

(: f (ListGenFunction Integer))

类似地,您应该为
生成列表
指定如下类型:

(: generate-list
   (All (A)
     ((ListGenFunction A) (ListGenLocFunction A) Integer -> (Listof A))))

这就像您明确地说您正在生成一个
(Listof a)
,而不仅仅是一个
Listof

啊,所以我可以(而且必须)标记类型!谢谢你把它清理干净!现在程序执行并产生正确的结果。尽管如此,DrRacket(Windows,版本5.3.3)还是显示了一个错误“类型检查器:宏扩展中的错误——不是有效的类型:(a)在:(define Type(listgenefunction a)(a->a))”。您知道为什么会显示此错误吗?由于程序基本上工作正常,这是误报吗?好的,5.2.1版(Debian版)没有这个问题。我想这可能是5.3.x中的一个小错误,也可能是Windows版本的一般错误。当您按“运行”时是否会出现此错误?或者其他地方?哦,对不起,我应该更具体一些:错误被标记在定义窗口中,并显示在状态栏中。它似乎是“独立的”。我的意思是,我不必执行程序,它只会出现。运行程序时没有任何错误,一切正常。我怀疑您在DrRacket中看到后台语法检查器的陈旧输出。如果您可以使用“运行”按钮运行该程序,则表示它已成功检查了类型(否则将不会执行)。
(: generate-list
   (All (A)
     ((ListGenFunction A) (ListGenLocFunction A) Integer -> (Listof A))))