Если вы посмотрите более внимательно, вы заметите, что Дух - это все о составе парсерных функций. Парсер - это просто функция, которая принимает сканер и возвращает матч. Parser функции составлены для формирования все более сложных форм более высокого порядка. Заметьте также, что парсер, хотя и объект, неизменный и постоянный. Все примитивные и композитные объекты являются const. Функция члена парса даже объявляется const:
Во всех аккаунтах это выглядит и очень похоже на Functional Programming. И действительно так. Дух - это, безусловно, применение функционального программирования в императивном домене C++. В Haskell, например, есть то, что называется парсерные комбинаторы, которые поразительно похожи на подход, принятый Духовно-парсерными функциями, которые состоят с использованием различных операторов для создания более высокого порядка парсерных функций, которые моделируют сверху вниз рекурсивный спусковой парсер. Эти умные люди Хаскелла делали это перед Духом.
Функциональные библиотеки программирования (или FP) набирают обороты в сообществе C++. Конечно, мы увидим больше FP в Духе сейчас и в будущем. На самом деле, если посмотреть более внимательно, даже стандартная библиотека C++ имеет вкус FP. Тщательно под ядром стандартной библиотеки C++ более пристальное внимание к STL дает нам представление о действительно существующей парадигме FP. Очевидно, что авторы STL знают и практикуют FP.
Semantic Actions in the FP Perspective
STL style FP
Более очевидное применение FP в стиле STL в Духе является семантическим действием. Что такое STL-стиль FP? Это в первую очередь использование функторов, которые могут быть составлены для формирования фукторов более высокого порядка.
Functors
A Function Object, or Functor is simply any object that can be called as
if it is a function. An ordinary function is a function object, and so is
a function pointer; more generally, so is an object of a class that defines
operator().
// Computes sin(x)/(x + DBL_MIN) for each element of a range.
transform(first, last, first,
compose2(divides<double>(),
ptr_fun(sin),
bind2nd(plus<double>(), DBL_MIN)));
Really, this is just currying in FP terminology.
Currying
What is "currying", and where does it come from?
Currying has its origins in the mathematical study of functions. It was
observed by Frege in 1893 that it suffices to restrict attention to functions
of a single argument. For example, for any two parameter function f(x,y),
there is a one parameter function f' such that f'(x) is
a function that can be applied to y to give (f'(x))(y) = f (x,y).
This corresponds to the well known fact that the sets (AxB -> C)
and (A -> (B -> C)) are isomorphic, where "x"
is cartesian product and "->" is function space. In
functional programming, function application is denoted by juxtaposition,
and assumed to associate to the left, so that the equation above becomes
f' x y = f(x,y).
В контексте Духа тот же FP стиль фанктора композиции может быть применен к семантическим действиям. full_calc.cpp - хороший пример. Вот фрагмент из этого образца:
Полный исходный код может быть просмотрен здесь. Это часть распространения Духа.
Boost style FP
Повышение принимает парадигму FP дальше. Есть библиотеки, которые специально сосредоточены на функциональных объектах и программировании более высокого порядка.
A utility library for passing references to generic
functions, from Jaako Järvi, Peter Dimov, Doug Gregor, and Dave Abrahams
Ниже приведен пример, который использует импульс Bind для использования функции члена в качестве семантического действия Духа. Этот пример можно увидеть в полном объеме в файле link.cpp.
Полный исходный код может быть просмотрен здесь. Это часть распространения Духа.
Этот парсер пересказывает список реальных чисел и хранит их в векторе<ДП>. Boost.bind создает Дух, соответствующий семантическому действию от функции list_parseradd.
Lambda and Phoenix
Есть библиотека, написанная вами по-настоящему, по имени Phoenix. Хотя это официально не является частью распространения Духа, эта библиотека широко использовалась для экспериментов над передовыми методами FP на C++. Эта библиотека в значительной степени зависит от FC++ и усилится Lambda (BLL).
BLL
In as much as Phoenix is influenced by boost Lambda (BLL),
Phoenix innovations such as local variables, local functions and adaptable
closures, in turn influenced BLL. Currently, BLL is very similar to Phoenix.
Most importantly, BLL incorporated Phoenix's adaptable closures. In the
future, Spirit will fully support BLL.
Феникс позволяет писать семантические действия в интерактивном виде на C++ через лямбда (неназванная функция) выражения. Вот фрагмент из phoenix_calc.cpp Пример:
Полный исходный код может быть просмотрен здесь. Это часть распространения Духа.
Вам не нужно беспокоиться о деталях на данный момент. Здесь многое происходит, что нужно объяснить. Последующие главы будут просветительными.
Обратите внимание на использование выражений ламбды, таких как:
expression.val += arg1
Lambda Expressions?
Lambda expressions are actually unnamed partially applied functions where
placeholders (e.g. arg1, arg2) are provided in place of some of the arguments.
The reason this is called a lambda expression is that traditionally, such
placeholders are written using the Greek letter lambda .
где expression.val является переменной закрытия правила выражения (см. Closures). arg1 является заполнителем первого аргумента, что семантическое действие получит (см. Phoenix Place-holders). В Boost.Lambda (BLL) это соответствует _1.
Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
Статья Functional раздела может быть полезна для разработчиков на c++ и boost.