Никогда не нравится визуальное представление call / cc, так как я не могу отразить это обратно в коде (да, плохое воображение);)
В любом случае, я думаю, что легче начать не с call / cc, а с call / ec (продолжение escape), если вы уже знакомы с исключениями на других языках.
Вот некоторый код, который должен оценить значение:
(lambda (x) (/ 1 x))
Что если x будет равен '0'? На других языках мы можем выбросить исключение, а как насчет схемы?
Мы тоже можем его бросить!
(lambda (x) (call/ec (cont)
(if (= x 0) (cont "Oh noes!") (/ 1 x))))
call / ec (как и call / cc) работает здесь как "try". В императивных языках вы можете легко выпрыгнуть из функции, просто возвращая значение или выбрасывая исключение.
В функционале вы не можете выпрыгнуть, вы должны что-то оценить. И вызов / * приходит на помощь.
Что он делает, он представляет выражение в «call / ec» как функцию (в моем случае это называется «cont») с одним аргументом. Когда эта функция вызывается, она заменяет ВЕСЬ вызов / * своим аргументом.
Итак, когда (cont "Oh noes!")
заменяет (call/ec (cont) (if (= x 0) (cont "Oh noes!") (/ 1 x)))
на "Oh noes!"
строку.
call / cc и call / ec почти равны друг другу, за исключением того, что их проще реализовать. Он позволяет только подпрыгивать, в то время как cc может быть спрыгнут снаружи.