为 typed/racket 中的向量定义 "minus function"
Defining a "minus function" for vectors in typed/racket
球拍新手。我一直在尝试制作一个简单的向量结构并定义常见的向量函数(点积、范数...)。我知道 math/matrix 但暂时不想使用它。
一切都很顺利,直到我尝试创建一个 "minus function" 来减去向量。加法函数工作正常,但减法会引发类型检查错误。这是代码:
#lang typed/racket
(struct: vect ([x : Real]
[y : Real])
#:transparent)
(: vect+ (-> vect * vect))
(define (vect+ . vs)
(vect (apply + (map vect-x vs))
(apply + (map vect-y vs))))
(: vect- (-> vect * vect))
(define (vect- . vs)
(vect (apply - (map vect-x vs))
(apply - (map vect-y vs))))
(vect+ (vect 1 2) (vect -3 1) (vect 0 4))
(vect- (vect 1 2) (vect -3 1) (vect 0 4))
vect+(向量加法)函数工作正常,但 vect- 函数引发:
. Type Checker: Bad arguments to function in `apply':
Domains: Number Number *
Arguments: (Listof Real) *
in: (apply - (map vect-x vs))
. Type Checker: Bad arguments to function in `apply':
Domains: Number Number *
Arguments: (Listof Real) *
in: (apply - (map vect-y vs))
. Type Checker: Summary: 2 errors encountered in:
(apply - (map vect-x vs))
(apply - (map vect-y vs))
为什么 "minus" 在 "plus" 接受实数并且下一行工作正常时拒绝实数?
(apply - (list 1 2 3))
; -> -4
我的猜测是减法的工作方式不同,因为 :
#lang racket
(- 5) ; -> -5
(- 5 3) ; -> 2
所以我定义了一个 neg 函数,它给出了向量的反函数,并为 vect- 定义了一个语法。很确定这是一种矫枉过正,但我不知道如何更简单地做到这一点。所以将它添加到代码中是可行的:
(: neg (-> vect vect))
(define (neg v)
(vect (- (vect-x v))
(- (vect-y v))))
(define-syntax vect-
(syntax-rules ()
[(vect- v) (neg v)]
[(vect- v1 v2 ...) (apply vect+ (list* v1 (map neg (list v2 ...))))]))
...但我很确定还有更好的方法。
错误是因为 apply
期望它的第一个参数是一个接受零个或多个参数的函数,但是 -
需要一个或多个参数(注意 +
有效,因为它接受零参数)。
> (:print-type apply)
(All (a b) (-> (-> a * b) (Listof a) b))
> (:print-type -)
; big output omitted,
; but notice it includes (-> Number Number * Number),
; but not (-> Number * Number))
> (-)
. Type Checker: could not apply function;
wrong number of arguments provided
expected at least: 1
given: 0 in: (-)
> (+)
- : Integer [more precisely: Zero]
0
为了解决这个问题,您可以 cast
apply
一个接受一个或多个函数作为其第一个参数的函数:
(: vect- (-> vect vect * vect))
(define (vect- . vs)
(define apply1+
(cast apply (All (a b) (-> (-> a a * b) (Listof a) b))))
(vect (apply1+ - (map vect-x vs))
(apply1+ - (map vect-y vs))))
(vect- (vect 1 2) (vect -3 1) (vect 0 4)) ; (vect 4 -3)
确保相应地更新 vect-
的类型。
或者,您可以定义一个接受零参数的替代减法函数:
(: new- (-> Real * Real))
(define (new- . args)
(if (empty? args)
0
(apply - args)))
(: vect- (-> vect * vect))
(define (vect- . vs)
(vect (apply new- (map vect-x vs))
(apply new- (map vect-y vs))))
在这里,可以给 vect-
个零参数。
(基于 stchang 的回答)
如果您将 vect-
的定义更改为此:
(: vect- (-> vect vect * vect))
(define (vect- v . vs)
(vect (apply - (vect-x v) (map vect-x vs))
(apply - (vect-y v) (map vect-y vs))))
这正是因为 -
不采用零参数。因此,apply
需要一些保证,至少会有一个论点。
球拍新手。我一直在尝试制作一个简单的向量结构并定义常见的向量函数(点积、范数...)。我知道 math/matrix 但暂时不想使用它。
一切都很顺利,直到我尝试创建一个 "minus function" 来减去向量。加法函数工作正常,但减法会引发类型检查错误。这是代码:
#lang typed/racket
(struct: vect ([x : Real]
[y : Real])
#:transparent)
(: vect+ (-> vect * vect))
(define (vect+ . vs)
(vect (apply + (map vect-x vs))
(apply + (map vect-y vs))))
(: vect- (-> vect * vect))
(define (vect- . vs)
(vect (apply - (map vect-x vs))
(apply - (map vect-y vs))))
(vect+ (vect 1 2) (vect -3 1) (vect 0 4))
(vect- (vect 1 2) (vect -3 1) (vect 0 4))
vect+(向量加法)函数工作正常,但 vect- 函数引发:
. Type Checker: Bad arguments to function in `apply':
Domains: Number Number *
Arguments: (Listof Real) *
in: (apply - (map vect-x vs))
. Type Checker: Bad arguments to function in `apply':
Domains: Number Number *
Arguments: (Listof Real) *
in: (apply - (map vect-y vs))
. Type Checker: Summary: 2 errors encountered in:
(apply - (map vect-x vs))
(apply - (map vect-y vs))
为什么 "minus" 在 "plus" 接受实数并且下一行工作正常时拒绝实数?
(apply - (list 1 2 3))
; -> -4
我的猜测是减法的工作方式不同,因为 :
#lang racket
(- 5) ; -> -5
(- 5 3) ; -> 2
所以我定义了一个 neg 函数,它给出了向量的反函数,并为 vect- 定义了一个语法。很确定这是一种矫枉过正,但我不知道如何更简单地做到这一点。所以将它添加到代码中是可行的:
(: neg (-> vect vect))
(define (neg v)
(vect (- (vect-x v))
(- (vect-y v))))
(define-syntax vect-
(syntax-rules ()
[(vect- v) (neg v)]
[(vect- v1 v2 ...) (apply vect+ (list* v1 (map neg (list v2 ...))))]))
...但我很确定还有更好的方法。
错误是因为 apply
期望它的第一个参数是一个接受零个或多个参数的函数,但是 -
需要一个或多个参数(注意 +
有效,因为它接受零参数)。
> (:print-type apply)
(All (a b) (-> (-> a * b) (Listof a) b))
> (:print-type -)
; big output omitted,
; but notice it includes (-> Number Number * Number),
; but not (-> Number * Number))
> (-)
. Type Checker: could not apply function;
wrong number of arguments provided
expected at least: 1
given: 0 in: (-)
> (+)
- : Integer [more precisely: Zero]
0
为了解决这个问题,您可以 cast
apply
一个接受一个或多个函数作为其第一个参数的函数:
(: vect- (-> vect vect * vect))
(define (vect- . vs)
(define apply1+
(cast apply (All (a b) (-> (-> a a * b) (Listof a) b))))
(vect (apply1+ - (map vect-x vs))
(apply1+ - (map vect-y vs))))
(vect- (vect 1 2) (vect -3 1) (vect 0 4)) ; (vect 4 -3)
确保相应地更新 vect-
的类型。
或者,您可以定义一个接受零参数的替代减法函数:
(: new- (-> Real * Real))
(define (new- . args)
(if (empty? args)
0
(apply - args)))
(: vect- (-> vect * vect))
(define (vect- . vs)
(vect (apply new- (map vect-x vs))
(apply new- (map vect-y vs))))
在这里,可以给 vect-
个零参数。
(基于 stchang 的回答)
如果您将 vect-
的定义更改为此:
(: vect- (-> vect vect * vect))
(define (vect- v . vs)
(vect (apply - (vect-x v) (map vect-x vs))
(apply - (vect-y v) (map vect-y vs))))
这正是因为 -
不采用零参数。因此,apply
需要一些保证,至少会有一个论点。