Scheme for/list中的球拍类型注释在查询中使用(DB调用)

Scheme for/list中的球拍类型注释在查询中使用(DB调用),scheme,racket,typed-racket,Scheme,Racket,Typed Racket,我试图从类型化Racket中的数据库中读取数据,并将其转换为结构列表。下面的代码是工作正常的非类型化版本。这是我能做的证明问题的最小的一点 #lang racket (require db) (define dbc (sqlite3-connect #:database "dmdb.sqlite3" #:mode 'read/write)) (struct player (name size str dex con base-hp current-hp base-ac attack) #:

我试图从类型化Racket中的数据库中读取数据,并将其转换为结构列表。下面的代码是工作正常的非类型化版本。这是我能做的证明问题的最小的一点

#lang racket

(require db)

(define dbc (sqlite3-connect #:database "dmdb.sqlite3" #:mode 'read/write))

(struct player (name size str dex con base-hp current-hp base-ac attack) #:mutable)

(define get-players
  (lambda (c)
    (for/list
        ([(n s str dex con bhp chp bac attack)
            (in-query c "select * from players")])
      (player n s str dex con bhp chp bac attack))))
程序的键入版本如下所示:

#lang type/racket
(require typed/db)

(: get-players (-> Connection (Listof player)))
(define get-players
  (lambda (c)
    (for/list
        ([(n s str dex con bhp chp bac attack)
            (in-query c "select * from players")])
      (player n s str dex con bhp chp bac attack))))
当我试图在键入的Racket中编译它时,我收到一些奇怪的错误消息:

Type Checker: Expression should produce 9 values, but produces 1 values of
types SQL-Datum in: (for/list (((n s str dex con bhp chp bac attack
(in-query c "select * from players"))) (player n s str dex con bhp chp bac
attack))

同样,只要没有键入代码,代码就可以正常工作。

看起来,即使键入的racket中的
for
语法支持多个值,您实际上无法在
键入的/racket
中键入多个值的序列。但是,可以使用将值序列转换为列表。从那里,您可以使用
定义值
将列表重新拆分为值,或者直接使用列表内联。对于您提供的函数,如下所示:

(: get-players (-> Connection (Listof player)))
(define (get-players c)
  (for/list ([a (in-values-sequence (in-query c "select * from players"))])
    (player (list-ref a 0)
            (list-ref a 1)
            (list-ref a 2)
            (list-ref a 3)
            (list-ref a 4)
            (list-ref a 5)
            (list-ref a 6)
            (list-ref a 7)
            (list-ref a 8))))

我怀疑这可能会对您的程序的性能产生影响,但我不能确定是什么。如果你想创建多个值的序列,你可以向上面的人寻求帮助,因为他们可能知道一些我不知道的东西。

在莱夫·安德森的帮助下,我找到了答案。下面是我可以创建的最小代码,它允许我测试我的解决方案。它涉及使用
查询行
而不是查询中的
来提取数据,然后处理生成的向量列表

#lang typed/racket
(require typed/db/base typed/db/sqlite3)


; for testing - cut and paste into interactions window
(define dbc (sqlite3-connect #:database "dmdb.sqlite3" #:mode 'read/write))

(struct player ([name : String] [size : String]
                [str : Integer] [dex : Integer] [con : Integer] [base-hp : Integer]
                [current-hp : Integer]
                [base-ac : Integer] [attack : Integer]) #:mutable )

(define lv (query-rows dbc "select * from players"))

(define ll : (Listof (Listof SQL-Datum))
    (for/list ((v lv))
      (vector->list v)))

(: lv->ll (-> (Listof (Vectorof SQL-Datum)) (Listof (Listof SQL-Datum))))
(define lv->ll
  (lambda (llv)
    (for/list ((v llv))
      (vector->list v))))

(: list->player (-> (Listof SQL-Datum) player))
(define list->player
  (lambda (a)
    (player (cast (list-ref a 0) String)
            (cast (list-ref a 1) String)
            (cast (list-ref a 2) Integer)
            (cast (list-ref a 3) Integer)
            (cast (list-ref a 4) Integer)
            (cast (list-ref a 5) Integer)
            (cast (list-ref a 6) Integer)
            (cast (list-ref a 7) Integer)
            (cast (list-ref a 8) Integer))))

(: list->playerlist (-> (Listof (Listof SQL-Datum)) (Listof player)))
(define list->playerlist
  (lambda (l)
    (for/list ((p l))
      (list->player p))))

(: listvectors->playerlist (-> (Listof (Vectorof SQL-Datum)) (Listof player)))
(define listvectors->playerlist
  (lambda (l)
    (list->playerlist (lv->ll l))))

(disconnect dbc)

我知道在某些圈子里,强制转换被认为是丑陋的,但我需要强制执行数据类型,我相信一旦程序出现,没有人会破坏数据库。如果他们把数据库搞砸了,我想这是他们自己的问题。

你从哪里得到
连接
类型?我忘了在第二个例子中包括#lang-typed/racket和(require-typed/DB)。我编辑了这篇文章来纠正这一点。谢谢你的注意。啊,好的,谢谢。我现在有了答案,写下来。太棒了!谢谢。有趣的解决方案,但至少在我的例子中,它会生成类型检查器之类的错误:多态函数'list ref'无法应用于参数:参数1:预期:(Listof a)给定:(Listof SQL数据)参数2:预期:整数给定:零结果类型:预期结果:字符串输入:(list ref a 0)(assert(list ref a 0)string?)(assert(list ref a 1)string?)似乎解决了前两个问题,但尝试使用integer?会给我类型检查器:预期类型不匹配:integer给定:(U不精确实整数)in:(assert(list ref a 2)integer?)它使用强制类型转换进行编译,但在执行过程中爆炸:在查询中:破坏了自己承诺的契约:生成了一系列1个值:9个值:'(“phred”“medium”14121)啊…嗯…我很难测试这个,因为我现在没有匹配的数据库。数据库目前都有5KB长。如果你需要,你可以通过gowinggl(at)nova.edu联系我(我是那里的教授)我非常感谢你的帮助。