With Haskell I have another feeling - when I do something with it I understand what I wanted by reading it in a slim snipet of code.
Part of vector-space package from Haskell may look like:
#include <iostream>
#include <complex.h>
namespace typeclasses
{
using std::pair;
/*
* based on: http://hackage.haskell.org/package/vector-space
*/
/* Concept:
* struct additive_group_traits<v>
* {
* static const v zero;
*
* static v sum(v, v);
* static v negate(v);
* };
*/
template <typename v>
struct additive_group_traits;
template <typename v>
v operator+(v a, v b)
{ return additive_group_traits<v>::sum(a, b); }
template <typename v>
v operator-(v a)
{ return additive_group_traits<v>::negate(a); }
template <typename v>
v operator-(v a, v b)
{ return additive_group_traits<v>::sum(a, -b); }
/* some instances */
template<>
struct additive_group_traits<int>
{
static const int zero = 0;
static int sum(int a, int b) { return (a+b); }
static int negate(int a) { return (-a); }
/* note: operator specialization should fire first */
};
template<>
struct additive_group_traits<float>
{
static const float zero = 0.0f;
static float sum(float a, float b) { return (a+b); }
static float negate(float a) { return (-a); }
};
template<>
struct additive_group_traits<double>
{
static const double zero = 0.0;
static double sum(double a, double b) { return (a+b); }
static double negate(double a) { return (-a); }
};
template<typename u, typename v>
struct additive_group_traits<pair<u, v> >
{
typedef pair<u, v> data;
typedef additive_group_traits<u> u_ag;
typedef additive_group_traits<v> v_ag;
//static const data zero = data(u_ag::zero, v_ag::zero);
static const data zero;
static data sum(data a, data b)
{ return data(a.first + b.first, a.second + b.second); }
static data negate(data a)
{ return data(-a.first, -a.second); }
};
template<typename u, typename v>
const pair<u, v> additive_group_traits<pair<u, v> >::zero =
pair<u, v>(additive_group_traits<u>::zero,
additive_group_traits<v>::zero);
/* Concepts:
* struct vector_space_traits<v>
* {
* typedef ... scalar_type;
*
* static v scale(scalar_type, v);
* };
*
* struct inner_space_traits<v>
* {
* static vector_space_traits<v>::scalar_type product(v, v);
* }
*/
template <typename v>
struct vector_space_traits;
template <typename v>
v operator*(typename vector_space_traits<v>::scalar_type k, v a)
{ return vector_space_traits<v>::scale(k, a); }
template <typename v>
v operator*(v a, typename vector_space_traits<v>::scalar_type k)
{ return vector_space_traits<v>::scale(k, a); }
template <typename v>
struct inner_space_traits;
template <typename v>
typename vector_space_traits<v>::scalar_type
vprod(v a, v b)
{ return inner_space_traits<v>::product(a, b); }
template <typename v>
v operator/(v a, typename vector_space_traits<v>::scalar_type k)
{ return vector_space_traits<v>::scale(1/k, a); }
// Linear interpolation between @a@ (when @t==0@) and @b@ (when @t==1@).
template <typename v>
v lerp(v a, v b,
typename vector_space_traits<v>::scalar_type t)
{ return (a + t * (b - a)); }
/* some instances */
template<>
struct vector_space_traits<double>
{
typedef double scalar_type;
static double scale(scalar_type k, double a) { return (k*a); }
};
template<>
struct vector_space_traits<float>
{
typedef float scalar_type;
static float scale(scalar_type k, float a) { return (k*a); }
};
template<typename u, typename v>
struct vector_space_traits<pair<u, v> >
{
typedef pair<u, v> data;
typedef vector_space_traits<u> u_vs;
typedef vector_space_traits<v> v_vs;
// TODO: assert that scalar types are equeal
typedef typename u_vs::scalar_type scalar_type;
static data scale(scalar_type k, data a)
{ return data(k * a.first, k * a.second); }
};
}
using namespace std;
using namespace typeclasses;
template <typename u, typename v>
ostream &operator<<(ostream &s, pair<u, v> x)
{ return (s << "(" << x.first << ", " << x.second << ")"); }
ostream &operator<<(ostream &s, double complex z)
{ return (s << "(" << creal(z) << " + " << cimag(z) << "*i)"); }
namespace typeclasses
{
template<>
struct additive_group_traits<double complex>
{
typedef double complex data;
static const data zero = 0.0;
static data sum(data a, data b) { return (a+b); }
static data negate(data a) { return (-a); }
};
template<>
struct vector_space_traits<double complex>
{
typedef double scalar_type;
static double complex scale(scalar_type k, double complex a)
{ return (k*a); }
};
}
int main()
{
pair<float, float> a = pair<float, float>(1, 1);
pair<float, float> b = pair<float, float>(13, 7);
pair<float, float> c = 3*(lerp(a, b, 1/3.f) - a);
cout << c << endl;
double complex za = 1 + 3*I;
double complex zb = 6 + 3*za;
cout << za << lerp(za, zb, 0.5) << zb << endl;
return 0;
}
#include <complex.h>
namespace typeclasses
{
using std::pair;
/*
* based on: http://hackage.haskell.org/package/vector-space
*/
/* Concept:
* struct additive_group_traits<v>
* {
* static const v zero;
*
* static v sum(v, v);
* static v negate(v);
* };
*/
template <typename v>
struct additive_group_traits;
template <typename v>
v operator+(v a, v b)
{ return additive_group_traits<v>::sum(a, b); }
template <typename v>
v operator-(v a)
{ return additive_group_traits<v>::negate(a); }
template <typename v>
v operator-(v a, v b)
{ return additive_group_traits<v>::sum(a, -b); }
/* some instances */
template<>
struct additive_group_traits<int>
{
static const int zero = 0;
static int sum(int a, int b) { return (a+b); }
static int negate(int a) { return (-a); }
/* note: operator specialization should fire first */
};
template<>
struct additive_group_traits<float>
{
static const float zero = 0.0f;
static float sum(float a, float b) { return (a+b); }
static float negate(float a) { return (-a); }
};
template<>
struct additive_group_traits<double>
{
static const double zero = 0.0;
static double sum(double a, double b) { return (a+b); }
static double negate(double a) { return (-a); }
};
template<typename u, typename v>
struct additive_group_traits<pair<u, v> >
{
typedef pair<u, v> data;
typedef additive_group_traits<u> u_ag;
typedef additive_group_traits<v> v_ag;
//static const data zero = data(u_ag::zero, v_ag::zero);
static const data zero;
static data sum(data a, data b)
{ return data(a.first + b.first, a.second + b.second); }
static data negate(data a)
{ return data(-a.first, -a.second); }
};
template<typename u, typename v>
const pair<u, v> additive_group_traits<pair<u, v> >::zero =
pair<u, v>(additive_group_traits<u>::zero,
additive_group_traits<v>::zero);
/* Concepts:
* struct vector_space_traits<v>
* {
* typedef ... scalar_type;
*
* static v scale(scalar_type, v);
* };
*
* struct inner_space_traits<v>
* {
* static vector_space_traits<v>::scalar_type product(v, v);
* }
*/
template <typename v>
struct vector_space_traits;
template <typename v>
v operator*(typename vector_space_traits<v>::scalar_type k, v a)
{ return vector_space_traits<v>::scale(k, a); }
template <typename v>
v operator*(v a, typename vector_space_traits<v>::scalar_type k)
{ return vector_space_traits<v>::scale(k, a); }
template <typename v>
struct inner_space_traits;
template <typename v>
typename vector_space_traits<v>::scalar_type
vprod(v a, v b)
{ return inner_space_traits<v>::product(a, b); }
template <typename v>
v operator/(v a, typename vector_space_traits<v>::scalar_type k)
{ return vector_space_traits<v>::scale(1/k, a); }
// Linear interpolation between @a@ (when @t==0@) and @b@ (when @t==1@).
template <typename v>
v lerp(v a, v b,
typename vector_space_traits<v>::scalar_type t)
{ return (a + t * (b - a)); }
/* some instances */
template<>
struct vector_space_traits<double>
{
typedef double scalar_type;
static double scale(scalar_type k, double a) { return (k*a); }
};
template<>
struct vector_space_traits<float>
{
typedef float scalar_type;
static float scale(scalar_type k, float a) { return (k*a); }
};
template<typename u, typename v>
struct vector_space_traits<pair<u, v> >
{
typedef pair<u, v> data;
typedef vector_space_traits<u> u_vs;
typedef vector_space_traits<v> v_vs;
// TODO: assert that scalar types are equeal
typedef typename u_vs::scalar_type scalar_type;
static data scale(scalar_type k, data a)
{ return data(k * a.first, k * a.second); }
};
}
using namespace std;
using namespace typeclasses;
template <typename u, typename v>
ostream &operator<<(ostream &s, pair<u, v> x)
{ return (s << "(" << x.first << ", " << x.second << ")"); }
ostream &operator<<(ostream &s, double complex z)
{ return (s << "(" << creal(z) << " + " << cimag(z) << "*i)"); }
namespace typeclasses
{
template<>
struct additive_group_traits<double complex>
{
typedef double complex data;
static const data zero = 0.0;
static data sum(data a, data b) { return (a+b); }
static data negate(data a) { return (-a); }
};
template<>
struct vector_space_traits<double complex>
{
typedef double scalar_type;
static double complex scale(scalar_type k, double complex a)
{ return (k*a); }
};
}
int main()
{
pair<float, float> a = pair<float, float>(1, 1);
pair<float, float> b = pair<float, float>(13, 7);
pair<float, float> c = 3*(lerp(a, b, 1/3.f) - a);
cout << c << endl;
double complex za = 1 + 3*I;
double complex zb = 6 + 3*za;
cout << za << lerp(za, zb, 0.5) << zb << endl;
return 0;
}
No comments:
Post a Comment