for/list 中的球拍类型注释使用查询中(数据库调用)
Racket type annotations in for/list using in-query (DB calls)
我正在尝试从类型化的 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))
同样,只要不输入,代码就可以完美运行。
看起来尽管 typed racket 中 for
的语法支持多个值,但实际上您无法对 typed/racket
中的多个值序列进行类型检查。但是,您可以使用 in-values-sequence
将值序列转换为列表。从那里,您可以使用 define-values
将列表拆分回值,或者只使用内联列表。对于您提供的功能,这看起来像:
(: 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))))
我怀疑这可能会影响您程序的性能,但我不能确定是什么。如果您想创建多个值的序列,您可以向 the racket mailing list 上的人寻求帮助,因为他们可能知道一些我不知道的事情。
在 Leif Andersen 的帮助下,我找到了答案。下面是我可以创建的允许我测试我的解决方案的最小代码。它涉及使用 query-rows
而不是 in-query
来提取数据,然后处理生成的向量列表。
#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)
我知道转换在某些圈子里被认为是丑陋的,但我需要强制数据类型,而且我相信一旦程序发布,没有人会破坏数据库。如果他们搞砸了他们的数据库,那是他们自己的问题,我猜。
我正在尝试从类型化的 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))
同样,只要不输入,代码就可以完美运行。
看起来尽管 typed racket 中 for
的语法支持多个值,但实际上您无法对 typed/racket
中的多个值序列进行类型检查。但是,您可以使用 in-values-sequence
将值序列转换为列表。从那里,您可以使用 define-values
将列表拆分回值,或者只使用内联列表。对于您提供的功能,这看起来像:
(: 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))))
我怀疑这可能会影响您程序的性能,但我不能确定是什么。如果您想创建多个值的序列,您可以向 the racket mailing list 上的人寻求帮助,因为他们可能知道一些我不知道的事情。
在 Leif Andersen 的帮助下,我找到了答案。下面是我可以创建的允许我测试我的解决方案的最小代码。它涉及使用 query-rows
而不是 in-query
来提取数据,然后处理生成的向量列表。
#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)
我知道转换在某些圈子里被认为是丑陋的,但我需要强制数据类型,而且我相信一旦程序发布,没有人会破坏数据库。如果他们搞砸了他们的数据库,那是他们自己的问题,我猜。