boost.spirit用户手册翻译(21):函数式

22 篇文章 0 订阅
 

Functional

函数式


 

If you look more closely, you'll notice that Spirit is all about composition of parser functions. A parser is just a function that accepts a scanner and returns a match. Parser functions are composed to form increasingly complex higher order forms. Notice too that the parser, albeit an object, is immutable and constant. All primitive and composite parser objects are const. The parse member function is even declared as const:

如果凑近些看,你会发现Spirit全是分析器函数的组合。一个分析器不过是一个接受扫描器并返回匹配的函数。分析器函数被组合起来以构成更高层次的形式。同时注意,对分析器而言,任意一个对象都是常量或者不变量。所有的元素或合成分析器对象都是const。甚至parse成员函数也同样被声明成const的:

    template <typename ScannerT>
    typename parser_result<self_t, ScannerT>::type
    parse(ScannerT const& scan) const;

In all accounts, this looks and feels a lot like Functional Programming. And indeed it is. Spirit is by all means an application of Functional programming in the imperative C++ domain. In Haskell, for example, there is what are called parser combinators which are strikingly similar to the approach taken by Spirit- parser functions which are composed using various operators to create higher order parser functions that model a top-down recursive descent parser. Those smart Haskell folks have been doing this way before Spirit.

就方方面面而言,这看起来像,感觉也像函数式编程。而且的确就是。Spirit就是一个想尽一切办法在命令式的C++领域里实现函数式编程的应用。比如,在Haskell里面,有一个叫分析器连接器的玩意,和Spirit里使用不同的操作符来组合分析器函数以构成更高层次的分析函数,从而形成一个自顶向下递归下降分析器的方法非常相似。Haskell聪明的作者们在Spirit之前已经这么干了。

Functional style programming (or FP) libraries are gaining momentum in the C++ community. Certainly, we'll see more of FP in Spirit now and in the future. Actually, if one looks more closely, even the C++ standard library has an FP flavor. Stealthily beneath the core of the standard C++ library, a closer look into STL gives us a glimpse of a truly FP paradigm already in place. It is obvious that the authors of STL know and practice FP.

函数式编程(FP)库正在C++社区中获得越来越多的能量。可以确定的是,从现在到将来,我们将在Spirit里看到更多的FP。实际上,如果看得更仔细些,会发现甚至C++标准库都有某些FP的特征。在标准库隐秘的核心之下,更仔细地观察,我们会看到一个真正的FP范式早已经在那儿了。很明显,STL的作者们了解并实践了FP。

Semantic Actions in the FP Perspective

FP视角下的语义动作

STL style FP

STL风格的FP

A more obvious application of STL-style FP in Spirit is the semantic action. What is STL-style FP? It is primarily the use of functors that can be composed to form higher order functors.

Spirit中一个更明显的STL风格的FP应用即语义动作。什么是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().

一个函数对象,或者说仿函数简单的说就是任意可以像函数那样被调用的对象。一个普通函数是一个函数对象,函数指针也是,更广泛的说,一个定义了operator()的类的对象也是如此。

This STL-style FP can be seen everywhere these days. The following example is taken from SGI's Standard Template Library Programmer's Guide:

这种STL风格的FP在今天已经随处可见。下面的例子来自于SGI的标准模板库程序员指南

    //  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.

其实,这只是FP名词学里所谓的currying罢了。

Currying

What is "currying", and where does it come from?

什么是"currying",它又是从哪儿来的?

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).

currying来自于对函数的数学研究。1893年Frege发现可以把注意力严格集中到只有一个参数的函数上。比如,对任意有两个参数的函数f(x,y),存在一个单参数函数f'比如f'(x)使得(f'(x))(y) = f (x,y)成立。 这对应于众所周知的事实:集合(AxB -> C) 和 (A -> (B -> C))等价。这里"x"是笛卡尔乘积且"->" 是函数空间。在函数式编程中,函数的使用写成并置的形式,并且认为是左关联的,因此上面的等式变成了f' x y = f(x,y)。

In the context of Spirit, the same FP style functor composition may be applied to semantic actions. full_calc.cpp is a good example. Here's a snippet from that sample:

在Spirit的语境里,同样FP风格的仿函数可以应用于语义动作,full_calc.cpp是一个很好的例子。这里是例子里的片段:

    expression =
        term
        >> *(   ('+' >> term)[make_op(plus<long>(), self.eval)]
            |   ('-' >> term)[make_op(minus<long>(), self.eval)]
            )
            ;

The full source code can be viewed here. This is part of the Spirit distribution.

可以在这里查看完整代码,这是Spirit发布包的一部分。

Boost style FP

Boost风格的FP

Boost takes the FP paradigm further. There are libraries in boost that focus specifically on Function objects and higher-order programming.

Boost在FP范式上走得更远。在boost里有不少专注于仿函数和高阶编程的库。

Boost FP libraries

Boost FP库

bind and mem_fn

bindmem_fn

Generalized binders for function/object/pointers and member functions, from Peter Dimov

为函数/对象/指针和成员函数生成绑定器。来自Peter Dimov

compose

Functional composition adapters for the STL, from Nicolai Josuttis

适用于STL的函数组合适配器,来自于Nicolai Josuttis

function

Function object wrappers for deferred calls or callbacks, from Doug Gregor

函数对象封装器,针对解引用调用或者回调,来自于Doug Gregor

functional

Enhanced function object adaptors, from Mark Rodgers

增强的函数对象适配器,来自于Mark Rodgers

lambda

Define small unnamed function objects at the actual call site, and more, from Jaakko Järvi and Gary Powell

在调用点定义小型的匿名函数对象,以及更多,来自于Jaakko Järvi 和Gary Powell

ref

A utility library for passing references to generic functions, from Jaako Järvi, Peter Dimov, Doug Gregor, and Dave Abrahams

把一个对象的引用传递给一般函数的工具库,来自于Jaako Järvi, Peter Dimov, Doug Gregor, 以及 Dave Abrahams

The following is an example that uses boost Bind to use a member function as a Spirit semantic action. You can see this example in full in the file bind.cpp.

下面是一个如何使用boost Bind 来把一个成员函数变成语义动作的例子。可以在bind.cpp看到完整的例子。

    class list_parser
    {
    public:

        typedef list_parser self_t;

        bool
        parse(char const* str)
        {
            return spirit::parse(str,

                //  Begin grammar
                (
                    real_p
                    [
                        bind(&self_t::add, this, _1)
                    ]

                    >> *(   ','
                            >>  real_p
                                [
                                    bind(&self_t::add, this, _1)
                                ]
                        )
                )
                ,
                //  End grammar

                space_p).full;
        }

        void
        add(double n)
        {
            v.push_back(n);
        }

        vector<double> v;
    };

The full source code can be viewed here. This is part of the Spirit distribution.

可以在这里查看完整代码,这是Spirit发布包的一部分。

This parser parses a comma separated list of real numbers and stores them in a vector . Boost.bind creates a Spirit conforming semantic action from the list_parser's member function add.

这个分析器分析一个由逗号分隔的实数列表并把它们储存到一个vector 。Boost.bind从list_parser的成员函数创建了一个符合Spirt标准的语义动作。

Lambda and Phoenix

Lambda 和 Phoenix

There's a library, authored by yours truly, named Phoenix. While this is not officially part of the Spirit distribution, this library has been used extensively to experiment on advanced FP techniques in C++. This library is highly influenced by FC++ and boost Lambda (BLL).

有一个库,由诚挚的本人写成的,名叫Phoenix。虽然还不是Spirit发布版的正式组成部分,但这个库已经被广泛地用来实验C++中的高级FP技术。这个库受到 FC++和boost 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.

由于Phoenix受到boost Lambda(BLL)的影响,Phoenix变革了诸如本地变量,本地函数和可适配闭包等受到BLL影响的概念。目前,BLL和Phoenix非常详细。最重要的是,BLL能与Phoenix的可适配闭包配合。将来,Spirit将对BLL提供完备的支持。

Phoenix allows one to write semantic actions inline in C++ through lambda (an unnamed function) expressions. Here's a snippet from the phoenix_calc.cpp example:


Phoenix允许在C++中通过λ(lambda,匿名函数)表达式写出内联的语义动作。这里是取自 phoenix_calc.cpp 中例子的一个片段:
    expression
        =   term[expression.val = arg1]
            >> *(   ('+' >> term[expression.val += arg1])
                |   ('-' >> term[expression.val -= arg1])
                )
        ;

    term
        =   factor[term.val = arg1]
            >> *(   ('*' >> factor[term.val *= arg1])
                |   ('/' >> factor[term.val /= arg1])
                )
        ;

    factor
        =   ureal_p[factor.val = arg1]
        |   '(' >> expression[factor.val = arg1] >> ')'
        |   ('-' >> factor[factor.val = -arg1])
        |   ('+' >> factor[factor.val = arg1])
        ;

The full source code can be viewed here. This is part of the Spirit distribution.

完整的代码可在此查阅。这是Spirit发布包的一部分。

You do not have to worry about the details for now. There is a lot going on here that needs to be explained. The succeeding chapters will be enlightening.

目前你不必为细节烦神。接下来还有很多东西要解释。紧接着的章节将有详细的讨论。

Notice the use of lambda expressions such as:

注意下面的λ表达式:

    expression.val += arg1

Lambda Expressions?

Lambda表达式?

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 .


Lambda表达式实际上是匿名的部分应用函数,其中的某些参数被占位符(如arg1,arg2等)替代。之所以把它称为lambda表达式是由于传统上,这样的占位符同样写成希腊字母lambda

where expression.val is a closure variable of the expression rule (see Closures). arg1 is a placeholder for the first argument that the semantic action will receive (see Phoenix Place-holders). In Boost.Lambda (BLL), this corresponds to _1.

expression.val是expression规则的一个闭包(见闭包)变量。arg1是语义动作将要接收的第一个参数的占位符(见Phoenix占位符)。在Boost.Lambda(BLL),对应的占位符为_1。

 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值