类型球拍 - 重新访问动态函数调用(字符串到过程)



大约一年前,@soegaard提供了一个有趣的问题的答案 - 如何获取字符串并返回该字符串中命名的过程。解决方案简单而优雅。

输入打字球拍和扭曲。

我可以让它在类型球拍中工作,只要它只返回具有相同参数的函数,例如(-> Number Number Number),但是如果我尝试让它能够返回具有不同参数的函数,如下所示,我无法弄清楚如何使 require/type 调用工作。

这是修改后的文件,其中包含我的第二个功能,具有不同的参数。

#lang racket
(provide string->procedure add square)
(define (add x y)
(+ x y))
(define (square x)
(sqr x))
(define ns (variable-reference->namespace (#%variable-reference)))
(define (string->procedure s)
(define sym (string->symbol s))
(eval sym ns))
(string->procedure "add")
((string->procedure "add") 1 2)
((string->procedure "square") 5)

这是仅适用于"add"功能或任何其他接受两个数字并返回一个数字的函数的调用。

#lang typed/racket
(require/typed "string-procedure.rkt"
[string->procedure
(-> String (-> Number Number Number))]
[add (-> Number Number Number)]
[square (-> Number Number)])

我尝试使用case->和工会无济于事。至少对返回类型使用case->将运行,但随后会失败所有调用。

如果您认为我尝试这个是疯了,我正在尝试做的是获取数据库调用的结果,一个字符串,并确定要调用的正确过程以访问结构中的相应数据元素。我可以用很长case的声明来做到这一点,但我希望有一个更优雅的解决方案。

谢谢。

我认为您不想使用eval,或者以这种方式解决此问题。具体来说:如果数据库包含引用不存在的函数或您不想调用的函数的字符串,该怎么办?这就是安全问题的产生方式。

我想说的是,在这种情况下,您可能愿意指定"合法"程序的名称,并且您可能可以使用不会破坏卫生的宏轻松做到这一点:

#lang typed/racket
;; defines the 'db-callable' syntax. Put this in a library file...
(define-syntax (db-callable stx)
(syntax-case stx ()
[(_ fun-name [id ...])
(with-syntax ([(id-strs ...)
(for/list ([id-stx (in-list (syntax->list #'(id ...)))])
(symbol->string (syntax-e id-stx)))])
#'(define (fun-name str)
(match str
[id-str id] ...)))]))
;; here are some functions we want the DB to be able to call
(define (f x) 3)
(define (g x) 4)
;; here's the list of functions we want the db to be able to call:
(db-callable getfun [f g])
((getfun "f") 9)
((getfun "g") 123)