2014-02-16 2 views
-1

Допустим, у меня есть следующие два файла:Коварство/Схема - пересмотреть внутреннюю функцию другого модуля

;; demo.scm 
(define-module (demo) 
    #:export (f)) 

(define (g x) 1) 
(define (f x) (g x)) 

... и в том же каталоге:

;; use-demo.scm 
(add-to-load-path ".") 
(use-modules (demo)) 

(define (g x) (+ x 1)) 
(display (f 5)) 
(newline) 

Запуск use-demo.scm в Коварство (2), Я получаю вывод 1. Таким образом, похоже, что функция f «закрыла» функцию g, которая определена в модуле demo. Есть ли способ обойти это? Я действительно хочу использовать версию g, которую я переопределил в use-demo.scm.

ответ

1

ОК, только для записи, я провел некоторое исследование и опубликовал решение этой конкретной проблемы в случае, если это кому-то поможет.

Хитрость заключается в том, чтобы не переопределить g локально, а скорее «Inject» новой функции в отображении в demo модуля имен к значениям.

(add-to-load-path ".") 
(use-modules (demo)) 

(module-define! (resolve-module '(demo)) 'g 
    (lambda (x) (+ x 1))) 

(display (f 5)) 
(newline) 
0

Если у вас есть конкретные функции, которые вы хотели бы иметь возможность переопределить, вы могли бы сделать их можно настроить с помощью parameters. Это имеет некоторые преимущества:

  1. Чтобы вернуть модуль в исходную конфигурацию, вам не нужно звонить reload-module.
  2. Изменения применяются только к области кода, для которой требуется модифицированное поведение.
  3. Он работает правильно при использовании нескольких потоков.

Очевидно, что основным недостатком является то, что вам нужно добавить шаблонного для каждой функции, которую вы хотите, чтобы быть переопределена (хотя это то, что гигиенические макросы для, хе-хе).

Этот код может работать. Я его не запускал.

;; demo.scm 

(define-module (demo) 
    #:export (f)) 

(define (default-g x) 1) 
(define p (make-parameter default-g)) 
(define (f x) ((p) x)) 


;; use-demo.scm 
(add-to-load-path ".") 
(use-modules (demo)) 

(define (my-g x) (+ x 1)) 
(parameterize ((@@ (demo) p) my-g) 
    (display (f 5)) 
    (newline)) 

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

+0

Спасибо, Питер. Я закончил это: https://github.com/yawaramin/ggspec/blob/7feaef3b00348cac8415ec1f47d3057496b81009/lib.scm#L81 – Yawar

+1

Хм. Ваша легкая структура модульного тестирования менее минимальна, чем моя (https://github.com/peter-b/geda-gaf/blob/master/libgeda/scheme/unit-test.scm). :-P Возможно, вы захотите украсть мою идею макроса 'assert-thrown'. –

+0

Очевидно, что в «реальной программе» ваш макрос 'stub' может быть ярким, если работает более одного потока, но он выглядит как отличное решение для тестирования! –

Смежные вопросы