Types 定义一个;负函数;对于类型化/球拍中的向量

Types 定义一个;负函数;对于类型化/球拍中的向量,types,racket,typed-racket,Types,Racket,Typed Racket,新的球拍。我一直在尝试制作一个简单的向量结构,并定义常见的向量函数(点积、范数…)。我知道数学/矩阵,但现在不想使用它 一切都很顺利,直到我尝试创建一个“减法函数”来减去向量。加法功能工作正常,但减法会导致打字错误。代码如下: #lang typed/racket (struct: vect ([x : Real] [y : Real]) #:transparent) (: vect+ (-> vect * vect)) (define (vect+

新的球拍。我一直在尝试制作一个简单的向量结构,并定义常见的向量函数(点积、范数…)。我知道数学/矩阵,但现在不想使用它

一切都很顺利,直到我尝试创建一个“减法函数”来减去向量。加法功能工作正常,但减法会导致打字错误。代码如下:

#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))
当“加号”接受了实数并且下面的行可以正常工作时,为什么“减号”会拒绝实数呢

    (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
希望它的第一个参数是一个接受零个或多个参数的函数,但是
-
需要一个或多个参数(注意
+
工作是因为它接受零个参数)

要解决此问题,您可以对接受一个或多个函数作为其第一个参数的函数应用
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的答案为基础)
> (: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
如果将
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
需要确保至少有一个参数

太好了,谢谢。我必须花一些时间来处理你的答案,因为它为我提出了新的概念——这很好。非常感谢。如果我是你,我会让neg和vect-成为独立的函数,而不会像racket的
-
函数那样将它们合并。但是如果你想在一个参数的情况下有不同的行为,有更好的方法。你不需要宏;你可以用case lambda来做。