Как использовать символические выражения, созданные функцией, для определения другой функции?

Я пытаюсь создать функцию символического вывода в схеме Chez. Работает нормально (упрощение еще не делается):

(define (derive var expr)
;; var is the direction in which you would like to derive
  (if (list? expr)
      (case (car expr)
        ('+    (sum-rule var expr))
        ('-    (sub-rule var expr))
        ('*    (prod-rule var expr))
        ;; other rules
        (else  (atomic-rule var expr )))
      (atomic-rule var expr)))

(define (atomic-rule var expr)
  (if (list? expr)
      expr
      (if (eqv? var expr)
          1
          0)))

(define (sum-rule var expr)
  (let ((args (cdr expr)))
    `(+ ,@(map (lambda (e) (derive var e)) args))))

(define (sub-rule var expr)
  (let ((args (cdr expr)))
    `(- ,@(map (lambda (e) (derive var e)) args))))

(define (prod-rule var  expr)
  (let* ((args (cdr expr))
         (f (car args))
         (g (cadr args)))
    `(+ (* ,f ,(derive var g))
        (* ,g ,(derive var f)))))

Я могу сделать(derive 'x '(+ (* x x) (* x y))) и получить (+ (+ (* x 1) (* x 1)) (+ (* x 0) (* y 1))), и это правильно. Но мне также хотелось бы программно создавать функции, которые возвращают числовые значения из этих выражений.

Мои попытки не увенчались успехом:

(define (lambda-derive var expr)
  (let ([derivative (derive var expr)])
    (lambda (var) derivative)))

((lambda-derive 'x '(* x x)) 2) => (+ (* x 1) (* x 1)) ;; should be 4

(define-syntax lbd-macro
  (lambda (context)
    (syntax-case context ()
      [(k expr var )
       (with-syntax ([new-var (datum->syntax #'k (syntax->datum #'var))])
         #'(lambda (new-var) expr))])))


((lbd-macro (derive 'x '(* x x)) x) 2) => (+ (* x 1) (* x 1)) ;; should be 4

Я чувствую, что упускаю что-то очень очевидное. Может ли кто-нибудь обеспечить свет? (Да, я знаю, что попытки не охватывают многомерные случаи)

==РЕДАКТИРОВАТЬ==

У меня была плохая ночь, и я решил продолжить работу, и я пришел к решению, аналогичному тому, что описал @ignis volens, хотя и с использованием хэш-таблиц и более хакерским подходом:

(define (lambda-aux variables vals expr)
  (let ((ht (make-eqv-hashtable (length variables))))
    (for-each (lambda (k v) (hashtable-set! ht k v)) variables vals)
    (let loop ((expr expr))
      (if (list? expr)
          (let ((op (car expr))
                (args (map loop (cdr expr))))
            (cons op args))
          (let ((variable (hashtable-ref ht expr #f)))
            (if variable
                variable
                (if (number? expr)
                    expr
                    (error "variable not found"))))))))

(define-syntax lambda-derive
  (syntax-rules ()
    [(_ expr var var* ...)
     (lambda (var var* ...) (eval (lambda-aux '(var var* ...) (list var var* ...) (derive 'var 'expr) )))]))

Что можно использовать так:

(define my-test-derivative
  ;;f(x,y) = x^2 + x * y
  ;;df/dx (x,y) = 2*x + y
  (lambda-derive (+ (* x y) (* x x)) x y))
(my-test-derivative 2 2) => 6
(my-test-derivative 8 2) => 18
;; ...
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это тот случай, когда вы либо хотите стиснуть зубы и использовать eval:

(eval `(lambda (x) ,(derive 'x '(* x x))) (scheme-report-environment 5))

вернет функцию одного аргумента, которая будет оценивать производную (* x x) для заданного значения x (здесь я предполагаю R5RS, поскольку у меня нет Chez Scheme):

> (let ((d (eval `(lambda (x) ,(derive 'x '(* x x))) (scheme-report-environment 5))))
    (d 1))
2

Или, что, возможно, лучше (и, конечно, безопаснее), вы можете написать средство оценки символических выражений. Опять же это R5RS:

(define (evaluate-symbolic-expression expression bindings)
  ;; Evaluate a symbolic expression in the presence of bindings
  (cond
    ((number? expression)
     expression)
    ((symbol? expression)
     (let ((found (assq expression bindings)))
       (if found
           (evaluate-symbolic-expression (cadr found) bindings)
           expression)))
    ((pair? expression)
     (apply-symbolic-operator
      (car expression)
      (map (lambda (e) (evaluate-symbolic-expression e bindings))
           (cdr expression))
      bindings))
    (else
     expression)))

(define (all-numbers? l)
  (cond
    ((null? l)
     #t)
    ((number? (car l))
     (all-numbers? (cdr l)))
    (else
     #f)))

(define (apply-symbolic-operator op args bindings)
  (if (all-numbers? args)
      (let ((f (assq op bindings)))
        (if f
         (apply (cadr f) args)
         `(,op ,@args)))
      `(,op ,@args)))

(define arithmetic-operator-bindings
  `((+ ,+)
    (- ,-)
    (* ,*)
    (/ ,/)))

И сейчас

> (evaluate-symbolic-expression
   (derive 'x '(* x x))
   (append '((x 4)) arithmetic-operator-bindings))
8

evaluate-symbolic-expression можно было бы написать более четко: все началось с реализации вычислителя для того, что по сути было крошечным Lisp-2, но я изменил его и было слишком лень все это переделывать.

Спасибо за вашу помощь! Между утверждением этого вопроса мне удалось решить его так же, как и вам (см. Редактирование). Я думаю, что оставлю этот вопрос открытым на некоторое время, и если никто не вмешается, отметьте ваше сообщение как решение.

nemo nemo 15.07.2024 16:13

Другие вопросы по теме