История изменений
Исправление quasimoto, (текущая версия) :
функция принимает и отдаёт абстрактный базовый класс. Однако срабатывает вовсе не эта функция, а вполне конкретная виртуальная, в зависимости от типа аргумента. Эта функция создаёт внутри себя результат, и отдаёт его наружу.
Ещё раз — Глобальное состояние в ФП (комментарий), показываешь как вот эта функция Add f(int(&a)(), int(&b)()) возвращает разные значения для одинаковых аргументов, без всех этих фантазий про что-то там не относящееся к моему утверждению что данная конкретная f чистая.
просто в C++ вовсе не классическое OOP, а своё, особое. Которое годно в частности и для обработки AST. Просто ты его не умеешь готовить.
В C++ классическое ООП. Я не могу не уметь его готовить, я же показываю примеры, то что ты хочешь это вот так — http://llvm.org/docs/tutorial/LangImpl7.html#id1 (иерархия class ExprAST), а ADT это вот так — http://llvm.org/docs/tutorial/OCamlLangImpl7.html#id1 (type expr в ast.ml), или так — http://github.com/sdiehl/kaleidoscope/blob/master/src/chapter7/Syntax.hs (data Expr), в C++ вот так — http://www.boost.org/doc/libs/1_55_0/libs/spirit/example/qi/compiler_tutorial... (boost::variant-ы).
засовывают. Говнокодеры.
При этом ты даже не знаешь о чём речь :) IORef в структуре это как мутабельное поле в классе.
для переменных и функций — без проблем. А про аппликации, это как это?
Аппликация это узел дерева в котором ты применяешь функцию к другому выражению, ну то есть вызов. Вот:
-- | Типизрованное лямбда исчисление -- дерево с тремя узлами.
data Term :: * -> * where
C :: a -> Term a -- ^ Переменные и примитивные значения с функциями.
A :: Term (a -> b) -> Term a -> Term b -- ^ Применение функции к выражению.
L :: (a -> Term b) -> Term (a -> b) -- ^ Анонимная функция.
-- | Интерпретатор.
eval :: Term a -> a
eval (C n) = n
eval (A e e') = eval e $ eval e'
eval (L e) = eval . e
test = L (\x -> C (+) `A` C x `A` C 3) `A` C 2
-- eval test
-- => 5
В test лямбда применяется к примитивной константе 2, в лямбде примитивная функция (+) дважды применяется к переменной лямбды x и примитивной константе 3. Тут используется HOAS, поэтому интерпретатор пишется легко без манипуляций с переменными и типизацией из коробки. Без HOAS (реализаций не пишу):
data Ty = B | Arr Ty Ty
data T = V | A T T | L (V, Ty) T
freeVars :: T -> [V]
subst :: V -> T -> T -> T
substV :: V -> V -> T -> T
alphaEq :: T -> T -> Bool
whnf :: T -> T
nf :: T -> T
betaEq :: T -> T -> Bool
check :: Env -> T -> Maybe Ty
Попробуй оба варианта HOAS / не-HOAS на C++ с наследованием / boost::variant.
нет, ты перепрыгнул. Именно ты написал сложение, которое берёт ссылки на функции, а возвращает структуру в которой сложение. И обосновал такое «сложение» тем, что при _умножении_ векторов может получаться скаляр.
Глобальное состояние в ФП (комментарий), конструктор узла дерева, иначе говоря. Ещё раз напишу — если дерево это Add r = r * r, то чистым конструктором будет r * r -> Add r, как я и написал. Почему дерево из одного узла? Ну дерево из нуля узлов это пустой тип — не интересно, из двух я написал выше — Formula r = r + Formula r * Formula r, так что чистый конструктор это уже Formula r * Formula r -> Formula r. Ну а в C++ это писать не досуг — итак смысл не в этом, а в том, что конструкторы AST чистые, его вычисление — нет, как анон хотел, только это всё нинужно в разговоре про чистые и нет функции в ЯП :)
Исходная версия quasimoto, :
функция принимает и отдаёт абстрактный базовый класс. Однако срабатывает вовсе не эта функция, а вполне конкретная виртуальная, в зависимости от типа аргумента. Эта функция создаёт внутри себя результат, и отдаёт его наружу.
Ещё раз — Глобальное состояние в ФП (комментарий), показываешь как вот эта функция Add f(int(&a)(), int(&b)()) возвращает разные значения для одинаковых аргументов, без всех этих фантазий про что-то там не относящееся к моему утверждению что данная конкретная f чистая.
просто в C++ вовсе не классическое OOP, а своё, особое. Которое годно в частности и для обработки AST. Просто ты его не умеешь готовить.
В C++ классическое ООП. Я не могу не уметь его готовить, я же показываю примеры, то что ты хочешь это вот так — http://llvm.org/docs/tutorial/LangImpl7.html#id1 (иерархия class ExprAST), а ADT это вот так — http://llvm.org/docs/tutorial/OCamlLangImpl7.html#id1 (type expr в ast.ml), или так — http://github.com/sdiehl/kaleidoscope/blob/master/src/chapter7/Syntax.hs (data Expr), в C++ вот так — http://www.boost.org/doc/libs/1_55_0/libs/spirit/example/qi/compiler_tutorial... (boost::variant-ы).
засовывают. Говнокодеры.
При этом ты даже не знаешь о чём речь :) IORef в структуре это как мутабельное поле в классе.
для переменных и функций — без проблем. А про аппликации, это как это?
Аппликация это узел дерева в котором ты применяешь функцию к другому выражению, ну то есть вызов. Вот:
-- | Типизрованное лямбда исчисление -- дерево с тремя узлами.
data Term :: * -> * where
C :: a -> Term a -- ^ Переменные и примитивные значения с функциями.
A :: Term (a -> b) -> Term a -> Term b -- ^ Применение функции к выражению.
L :: (a -> Term b) -> Term (a -> b) -- ^ Анонимная функция.
-- | Интерпретатор.
eval :: Term a -> a
eval (C n) = n
eval (A e e') = eval e $ eval e'
eval (L e) = eval . e
test = L (\x -> C (+) `A` C x `A` C 3) `A` C 2
-- eval test
-- => 5
В test лямбда применяется к примитивной константе 2, в лямбде примитивная функция (+) дважды применяется к переменной лямбды x и примитивной константе 3. Тут используется HOAS, поэтому интерпретатор пишется легко без манипуляций с переменными и типизацией из коробки. Без HOAS (реализаций не пишу):
data Ty = B | Arr Ty Ty
data T = V | A T T | L (V, Ty) T
freeVars :: T -> [V]
subst :: V -> T -> T -> T
substV :: V -> V -> T -> T
alphaEq :: T -> T -> Bool
whnf :: T -> T
nf :: T -> T
betaEq :: T -> T -> Bool
check :: Env -> T -> Maybe Ty
Попробуй оба варианта HOAS / не-HOAS на C++ с наследованием / boost::variant.
нет, ты перепрыгнул. Именно ты написал сложение, которое берёт ссылки на функции, а возвращает структуру в которой сложение. И обосновал такое «сложение» тем, что при _умножении_ векторов может получаться скаляр.
Глобальное состояние в ФП (комментарий), конструктор узла дерева, иначе говоря. Ещё раз напишу — если дерево это Add r = r * r, то чистым конструктором будет r * r -> Add r, как я и написал. Почему дерево из одного узла? Ну дерево из нуля узлов это пустой тип — неинтересно, из двух я написал в выше — Formula r = r + Formula r * Formula r, так что чистый конструктор это уже Formula r * Formula r -> Formula r. Ну а в C++ это писать не досуг — итак смысл не в этом, а в том, что конструкторы AST чистые, его вычисление — нет, как анон хотел, только это всё нинужно в разговоре про чистые и нет функции в ЯП :)