LINUX.ORG.RU

История изменений

Исправление 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 чистые, его вычисление — нет, как анон хотел, только это всё нинужно в разговоре про чистые и нет функции в ЯП :)