Всем привет! Мне сегодня не дали закончить предложение по докладам, которые я мог бы сделать, так что я решил просто запостить часть тут. Второе моё (неозвученное) предложение касалось того, как решают проблему визиторов в функциональном мире. Проблема, которую решает Визитор известна как Expression Problem, её сформулировал Филипп Вадлер в 1998 году. Как видно из Википедии, есть несколько работ, которые её решают разными способами.
Есть ещё работа Datatypes a la Carte (также JFP, 2008), которую мой студент Владимир Панков использовал в своей бакалаврской в прошлом году.
И есть ещё статья Оливейры и коллеги про объектные алгебры (конференция ECOOP, 2012). Там явно сказано, что они решают проблему Визитора.
Вот простое решение (Ideone) Киселёва. Интересно было бы услышать критику. Можно на следующем докладе.
-- Определяем типы (алгебру) узлов дерева (int, add, …)
class Algebra rep where
int :: Int -> rep Int
add :: rep Int -> rep Int -> rep Int
lam :: (rep a -> rep b) -> rep (a -> b)
app :: rep (a -> b) -> rep a -> rep b
-- «Визитор»-вычислитель дерева выражения: объявление
newtype Eval a = E {unE :: a}
-- «Визитор»-вычислитель дерева выражения: определение
instance Algebra Eval where
int = E
add x y = E (unE x + unE y)
lam f = E (unE . f . E)
app f x = E ( (unE f) (unE x) )
-- «Визитор»-измеритель глубины дерева выражения: объявление
newtype Depth a = D {unD :: Int}
-- «Визитор»-измеритель глубины дерева выражения: определение
instance Algebra Depth where
int _ = D 1
add x y = D (1 + max (unD x) (unD y))
lam f = D (1 + unD (f (D 0)))
app f x = D (1 + max (unD f) (unD x))
-- Пример дерева: (\x -> x + 2) 1
test2 :: Algebra rep => rep Int
test2 = app (lam (\x -> add x (int 2))) (int 1)
-- Основная программа: печатает результат вычисления test2 и его высоту
main = print $ (unE test2, unD test2) -- (3, 4)
Замечу, что я мог бы ограничиться сложением и целыми числами, но в сегодняшнем докладе были переменные и хотелось, чтобы и тут они появились. Кодирование Киселёва не позволяет оставлять свободные переменные, так как это мешает типизации всего выражения. Но связанные переменные — в лямбда-функциях — это пожалуйста. Так что пришлось добавить лямбда-абстракцию. Ну и аппликацию, чтобы можно было написать пример с лямбдой, который распечатается на консоль (то есть чтобы в результате у визитора-вычислителя было число).
Это одни из наиболее цитируемых и влиятельных статей в области языков программирования, если верить википедии и Бенджамину Пирсу. Статьи по теории типов и лямбда-исчислению в списке ниже я (пока) не привожу.
Следующий доклад на семинаре состоится в ближайшую пятницу (1 апреля), в 16:00, примерная тема доклада: «Язык с уточнёнными типами (refinement types)», докладчик: В. Квачёв, студент 3-го курса ФИИТ. Приглашаются все желающие.