CASE-TEST: ( CASE "Apple" ( ( ( < 5 ) ( FORMAT "Less than 5~%" ) ) ( ( = 5 ) ( FORMAT "Equals 5~%" ) ) ( ( > 5 ) ( FORMAT "Greater than 5~%" ) ) ( ( = "Apple" ) ( FORMAT "It's an apple!~%" ) ) ) ( FORMAT "I dont know what is it~%" ) )
Вычисление этого кода печатает "It's an apple!".
В общем виде структура такая:
( CASE (expr) ( ( ( cond-p-1 ) ( instr-1 ) ) ( ( cond-p-2 ) ( instr-2 ) ) .. ( ( cond-p-n ) ( instr-n ) ) ) ( when-not-of-it-all-instr ) )
Что неудобно: если вместо правильных одноместных предикатов (функций одного параметра, возвращающих булеву истину, если выполнено некое условие, запрограммированное в этой самой функции) указан вызов какой-нибудь обычной функции, например ( > 5 ), то к списку её кода пристыковывается результат вычисления expr и получается так:
( > 5 expr )
Что даёт результат, совершенно противоположный очевидно-ожидаемому: например, если expr было равно 2, то записав условие в виде ( > 5 ) мы будем ожидать, что этот предикат НЕ сработает, в то время как в реальности ( > 5 2 ) возвращает, очевидно, T и далее вызывается связанный с этим условием код.
Очевиден так же и метод обхода, хоть он и немного громоздкий - в качестве предикатов для неких "временных", нужных только в этом месте, условий, надо использовать лямбды! Т.е. на месте ( > 5 ) надо записать как-то так:
(apply ( lambda (x) ( > x 5 ) ) )
Этот код должен работать правильно. И сейчас я это проверю...
...
????
!!!!
...
( CASE "Apple" ( ( ( = 5 ) ( FORMAT "Equals 5~%" ) ) ( ( APPLY ( LAMBDA ( X ) ( > X 5 ) ) ) ( FORMAT "Less than 5~%" ) ) ( ( APPLY ( LAMBDA ( X ) ( < X 5 ) ) ) ( FORMAT "Greater than 5~%" ) ) ( ( APPLE-P ) ( FORMAT "It's an apple!~%" ) ) ) ( FORMAT "I dont know what to do with ~a~%" $ ) ) It's an apple!
Сами логичские функции ещё оооочень далеки от совершенства в части касающейся сравнения данных разных типов (сейчас всё просто - если тип не совпадает, возвращается NIL, даже если мы сравниваем целочисленный 0 и, например, null-строку (не пустую, которая "", а вообще null)).
APPLE-P это как раз предикат, который проверяет равенство своего аргумента строке "Apple".
$ - это локальный символ, которому присваивается вычисленное значение expr. Вот что будет, если тот же CASE запустить с чем-то, чего он не знает:
( CASE "Pineapple" ( ( ( = 5 ) ( FORMAT "Equals 5~%" ) ) ( ( APPLY ( LAMBDA ( X ) ( > X 5 ) ) ) ( FORMAT "Less than 5~%" ) ) ( ( APPLY ( LAMBDA ( X ) ( < X 5 ) ) ) ( FORMAT "Greater than 5~%" ) ) ( ( APPLE-P ) ( FORMAT "It's an apple!~%" ) ) ) ( FORMAT "I dont know what to do with ~a~%" $ ) ) I dont know what to do with "Pineapple"
РАБОТАЕТ!
Правда, это совсем не то же самое, что CASE в Common Lisp. И не совсем COND. Переименовал в "SELECTOR", пусть будет.. и тут же, пока горячо, накропал более привычный и почти стандартный CASE. Отличие только одно - не используется слово "otherwise", вместо этого код для "никакого" условия вынесен как бы в отдельную ветку. Вот:
( CASE "Beta" ( ( "Kenobi" "Jedi" ) ( ( 5 99 1024 ) "Kinda integer" ) ( ( "Alpha" 1 "Beta" ) ( FORMAT "UncommonLisp is awesome!~%" ) ) ) ( FORMAT "I dont know what to do with ~a~%" $ ) ) UncommonLisp is awesome!