How do I handle a variable number of arguments passed to a function in Racket?

前端 未结 3 523
名媛妹妹
名媛妹妹 2021-01-19 16:15

I like creating functions which take an unlimited number of arguments, and being able to deal with them as a list. It\'s been useful to me when creating binary trees & I

3条回答
  •  终归单人心
    2021-01-19 16:53

    Your list is not improper. When your argument is not a pair, like (lambda xs body ...) or (define (fun . xs) body ...) all your arguments gets slurped into a list. Eg.. (fun 1 2 3) would make xs '(1 2 3). Doing (list* '(1 2 3) '()) makes '((1 2 3) which you undo right away by calling your loop with car which makes it '(1 2 3) again.

    Other than that your procedure works as intended. You might clean up your procedure a little, but since there is no list comprehensions that glides over a list folding over the two next elements it won't become much smaller. Below is basically the same code, but abstracting out the procedure that does the work (which if existed a foldl-pair you could have used) and with a named let as a iterator loop (which is syntactic sugar for a letrec+call).

    (define (distance-between e1 . lst)
      (define (add-diff-acc e1 e2 acc)
        (+ (abs (- (map-node-x e1) (map-node-x e2)))
           (abs (- (map-node-y e1) (map-node-y e2)))
           acc))
    
      (let iterate ((e1 e1) (lst lst) (acc 0))
        (if (pair? lst)
            (let ((e2 (car lst)))
              (iterate e2 (cdr lst) (add-diff-acc e1 e2 acc)))
            acc)))
    

    EDIT: About syntax sugar, named let and letrec.

    (let ((x 10) (y 19)) 
      body)
    

    is syntactic sugar for a anonymous procedure call

    ((lambda (x y) 
        body) 
      10 19)
    

    A named let is just giving that procedure a name, though as if by letrec, making a recursive binding. you call it with the name you give and the arguments will be what you supply instead of the initial value in the let. I'm used to them and prefer them today. It might take some time to get used to though.

    Most of the code we write is syntactic sugar for some lower level stuff. The macros are nested so that your letrec form could get reduced down lambdas eventually. The whole procedure without syntactic sugar would look like this:

    (define distance-between 
      (lambda (e1 . lst)
        ((lambda (add-diff-acc)
           ((lambda (iterate e1 lst acc) ; emulate Y to substitute `letrec`
              (iterate iterate e1 lst acc))
            (lambda (iterate e1 lst acc)
              (if (pair? lst)
                  ((lambda (e2)
                     (iterate iterate e2 (cdr lst) (add-diff-acc e1 e2 acc)))
                   (car lst))
                  acc))
            e1 lst 0))
         (lambda (e1 e2 acc)
           (+ (abs (- (map-node-x e1) (map-node-x e2)))
              (abs (- (map-node-y e1) (map-node-y e2)))
              acc)))))
    

提交回复
热议问题