Racket:如何将参数的值用作符号?

huangapple go评论58阅读模式
英文:

Racket: How do you use the value of an argument as a symbol?

问题

我理解了您的请求,以下是您提供的代码部分的翻译:

#lang racket

(define (ul . xs) `(div ,@xs))

(define (make-list list-type)
  (if (equal? 'something 'something-else)
    (λ args (apply list-type args)) ; 真分支:调用函数 "ul"
    (λ args (list* list-type args)))) ; 假分支:如何使用 'ul 而不调用 "ul" 函数?

(define make-ul (make-list 'ul))

请注意,我已经将 ul'ul 更改为 'ul,以确保它被识别为符号。

英文:

I'm new to Racket, and am struggling to find the right words to explain what I'm trying to do. The best I can come up with is this: How do I use the value of an argument as a symbol, without calling the function which has the same name as the value of the argument, and without just quoting the name of the argument?

Here is a minimal example to show this.

There is a function called ul which does something.

There is another function called make-list which has a single parameter, list-type.

There is a third function, make-ul, which calls make-list with an argument ul.

In the true branch, the function ul is applied. Good so far.

In the false branch, I want to be able to use the value of the argument, which in this case is 'ul, as a symbol. In effect, this line of code would run (λ args (list* 'ul args)). How do I achieve this?

#lang racket

(define (ul . xs) `(div ,@xs))

(define (make-list list-type)
  (if (equal? 'something 'something-else)
    (λ args (apply list-type args)) ; true branch: call the function "ul"
    (λ args (list* list-type args)))) ; false branch: how to use `ul without calling the "ul" function?

(define make-ul (make-list ul))

答案1

得分: 2

If your goal is to write good Racket code, then the best answer is don't.
Add a separate argument to take the symbol, like this:

;; make-list: Procedure Symbol -> Any ... -> Any
(define (make-list proc tag-sym)
  (if ....
      proc ;; (λ args (apply proc args)) simplifies to just proc
      (λ args (list* tag-sym args))))
(define make-ul (make-list ul 'ul))

Or if the branch is independent of args, you could just have a single argument of type (U Procedure Symbol) instead:

;; make-list: (U Procedure Symbol) -> Any ... -> Any
(define (make-list list-type)
  (cond [(procedure? list-type)
         ;; (λ args (apply list-type args))
         list-type]
        [(symbol? list-type)
         (λ args (list* list-type args))]))
(define make-ul (make-list ul))
(define make-li (make-list 'li))

If you want to explore Racket features, there are two main ways to do it.

  1. You can make a macro that takes a procedure name and uses it both as a reference and quotes it as a symbol. For example, using the first version of make-list above:
(define-syntax-rule (make-list* proc-name) (make-list proc-name (quote proc-name)))

(define make-ul (make-list* ul)) ;; => (define make-ul (make-list ul 'ul))
  1. You can call object-name on a procedure to ask what Racket thinks its name is. For example, (object-name list) returns 'list, and (object-name ul) should return 'ul. But (object-name make-ul) will not return 'make-ul, because Racket tracks names at compile time, not at run time. (I would advise against writing code that depends on object-name; it makes your code very fragile.)
英文:

If your goal is to write good Racket code, then the best answer is don't.
Add a separate argument to take the symbol, like this:

;; make-list : Procedure Symbol -> Any ... -> Any
(define (make-list proc tag-sym)
  (if ....
      proc ;; (λ args (apply proc args)) simplifies to just proc
      (λ args (list* tag-sym args))))

(define make-ul (make-list ul 'ul))

Or if the branch is independent of args, you could just have a single argument of type (U Procedure Symbol) instead:

;; make-list : (U Procedure Symbol) -> Any ... -> Any
(define (make-list list-type)
  (cond [(procedure? list-type)
         ;; (λ args (apply list-type args))
         list-type]
        [(symbol? list-type)
         (λ args (list* list-type args))]))

(define make-ul (make-list ul))
(define make-li (make-list 'li))

If you want to explore Racket features, there are two main ways to do it.

  1. You can make a macro that takes a procedure name and uses it both as a reference and quotes it as a symbol. For example, using the first version of make-list above:

     (define-syntax-rule (make-list* proc-name) (make-list proc-name (quote proc-name)))
    
     (define make-ul (make-list* ul)) ;; => (define make-ul (make-list ul 'ul))
    
  2. You can call object-name on a procedure to ask what Racket thinks its name is. For example, (object-name list) returns 'list, and (object-name ul) should return 'ul. But (object-name make-ul) will not return 'make-ul, because Racket tracks names at compile time, not at run time. (I would advise against writing code that depends on object-name; it makes your code very fragile.)

huangapple
  • 本文由 发表于 2020年1月3日 22:19:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/59580144.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定