|
Boost Users : |
Subject: [Boost-users] [proto] learning proto slowly, a small (math)complex library
From: alfC (alfredo.correa_at_[hidden])
Date: 2011-01-10 05:47:44
Hi,
I find proto pretty intriguing and I can see the power in it but I am
still not able to create a context in which it can help in my design.
I also find the Boost.Proto examples very confusing and not usually in
the context I always imagine to use the library. There are several
concepts that I don't yet fully understand like "context" and
"grammars". Also besides the power I see in the library sometimes the
resulting syntax in the examples is pretty disappointing, with all
those "eval" functions. In general I can't see whether this is a
result of limitations of the library or a tool to make the examples
more pedagogical.
If someone is kind enough to follow me and help me during this
discovery of the library along these posts I will continue. The idea
of this post is try to bring a simple example of boost at a context
that I am able to understand. In order to be useful for many other
people I will try to bring proto to a purely mathematical level.
Suppose I want to build a new (kind of mathematical) library.
Typically I would start defining a lots of arithmetical objects and
members and friends operators, all of them eager (member)functions,
lots of operators (many bugs also), also use boost.operators (to make
less bugs) and then realise that the library has not any real deep
mathematical structure on it, not to the compile-time/programmer
level. Yes, the program will be able to do a lot of mathematics at
runtime via numerical representations but there will be no insight
from the point of view of the program code or the "type system".
Let's start by an example, I define a complex type, after a lot of
work I would have made the equivalent of std::complex<T>. Then the
program replaces T by double and the program can (at runtime) do some
"math". The problem is that I as a programmer can not do any math with
that type. Let me give a concrete example, the complex_unit_circle is
a set of complex numbers with modulus =1. One is tempted to implement
complex_unit_circle in terms of the "complex type" or some
parameterisation (angle).
>From a mathematical point of view the complex z is a complex number of
course, and z/|z| (z/abs(z)) is not only also a complex number but
also potentially a complex_unit_circle element with very spefic
properties. For example the product of two elements of the unit circle
can be interpreted as a unit circle element again. The only way to
express this potentiality at compile time is by expression templates,
i.e. in its most glorious state by Boost.Proto. z/abs(z) is really an
expression that eventually can be used to construct either another
complex number (as type) or a unit circle number (as type).
But lets start slower than that, lets build an expression that can be
used (potentially) to build a complex number instead.
The concrete question of this post will be how to obtain the desired
syntax by adding layers to the original posted code.
This is what I have done so far:
#include <boost/proto/core.hpp>
namespace pretty{
namespace proto = boost::proto;
struct i_tag{};
proto::terminal< i_tag >::type const i = {{}};
}
int main(){
using namespace pretty;
4. + 5.*i; //this will be a complex number (in some sense)
return 0;
}
of course this program does nothing, it is just to show that I can
create a expression template with a symbol called "i", this symbol
will have properties that will eventually make it equivalent to one of
the roots of -1 (mathematically speaking) (but not yet). Note that I
didn't define any so called "grammar" or "context" yet.
Since the first concern is to be able to use the new code with old
code at all intermediate steps in the development, duppose I want to
use this kind of expression to construct (in the c++ sense) an
existing type, namely std::complex<double>. i.e. I want to be able to
write:
std::complex<double> z = 4. + 5.*i;
or
std::complex<double> z(4. + 5.*i);
(forget about alternative notations, like 5.*i + 4. or 4. + i*5)
The only ways I see this is possible is by adding either a constructor
to std::complex<double> or a cast operator of the "expression of type
4.+5.*i" to std::complex<double>.
The question for this post,
1) is this true?
2) if yes, then that means that one of the 2 types (type complex or
typeof(4.+5.*i) ), will have to be modified (or extendended) in other
to accept this syntax.
3) if no , how can I allow this syntax?
4) if the std::complex type is not modifiable, what is the mechanism
in proto to define a cast over a certain set of expressions, e.g. of
the type of 4.+5.*i.
5) if not, is this syntax not possible at all? is it here where we
need to introduce those "eval" functions such as std::complex<double>
z = eval_as_complex(4. + 5.*i).
The idea is that once I resolve this general questions about the
library I will continue building up. (And excuse me for these naive
questions along the way).
(Note: I know that std::complex<double> had constructor
std::complex<double>(4.,5.) and that should be the preferred use, but
this post is all about "syntax" and how to use proto, these are just
examples).
Thank you,
Alfredo
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net