Makro rakiety do automatycznego definiowania funkcji podanych na liście
Chcę automatycznie wygenerować kilka funkcji testowych z listy. Zaletą jest to, że mogę zmienić listę (np. Przez odczytanie tabeli danych CSV), a program automatycznie wygeneruje różne testy następnego wykonania programu.
Na przykład powiedz, że próbuję zidentyfikowaćoksyany w ciągu zawierającym awzór chemiczny.
Moja lista może być następująca:
(define *oxyanion-tests*
; name cation
(list (list "aluminate" "Al")
(list "borate" "B")
(list "gallate" "Ga")
(list "germanate" "Ge")
(list "phosphate" "P")
(list "sulfate" "S")
(list "silicate" "Si")
(list "titanate" "Ti")
(list "vanadate" "V")
(list "stannate" "Sn")
(list "carbonate" "C")
(list "molybdate" "Mo")
(list "tungstate" "W")))
Jestem przekonany, że wzór chemiczny zawiera jeden z nichoksyany jeśli występuje kation, po którym następuje tlen w nawiasach (np. „(O3)”), lub jeśli po kationie następują 2 lub więcej atomów tlenu (np. „C03”). Zauważ, że to nie jest idealne, ponieważ będzie brakowało anionów podchlorynowych (np. „Cl O”), ale jest wystarczająco dobre dla mojej aplikacji.
(define ((*ate? elem) s-formula)
(or (regexp-match? (regexp (string-append "\\(" elem "[0-9.]* O[0-9.]*\\)")) s-formula)
(regexp-match? (regexp (string-append "(^| )" elem "[0-9.]* O[2-9][0-9.]*")) s-formula)))
Myślę, że potrzebuję makra, aby to zrobić, ale tak naprawdę nie rozumiem, jak działają, czytając dokumentację. Pytam tutaj, abym miał dobry przykład, który mi się przyda.
Oto, o czym myślę, że makro powinno wyglądać, ale nie działa i tak naprawdę nie mam mentalnego modelu, aby dowiedzieć się, jak to naprawić.
(require (for-syntax racket))
(define-syntax-rule (define-all/ate? oxyanion-tests)
(for ([test oxyanion-tests])
(match test
[(list name cation) (syntax->datum (syntax (define ((string->symbol (string-append name "?")) s-formula)
((*ate? cation) s-formula))))])))
Dziękujemy za wszelkie wskazówki, które możesz mi dać!
P.S. Oto kilka testów, które powinny przejść:
(define-all/ate? *oxyanion-tests*)
(module+ test
(require rackunit)
(check-true (borate? "B O3"))
(check-true (carbonate? "C O3"))
(check-true (silicate? "Si O4")))