请选择 进入手机版 | 继续访问电脑版

开源计算机图形学社区(Open Source Computer Graphics Community) |OpenGPU Forum (2007-2013)| OpenGPU Project

 找回密码
 注册
搜索
查看: 1245|回复: 0

使用simulation模板库进行纯函数式编程 [复制链接]

Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20

注册时间
2016-6-20
积分
470
发表于 2016-6-20 20:30:48 |显示全部楼层
使用simulation模板库进行纯函数式编程。
用这种方法可以表达一切程序。

有C++的和C#的。
先发C#的。
注意里面要用到C++的lambda表达式。

附带一个例子,太阳地球仿真。

C#的:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Simulation
{
     interface IUpdate
     {
         void Update();
             void Flush();
     }

     class Manager // 这是管理器,每帧需要对它进行update和flush
     {
         public static Manager TheManager = new Manager();
         private LinkedList<IUpdate> Updates = new LinkedList<IUpdate>();
             public void Add(IUpdate update)
             {
                     Updates.AddLast(update);
             }
             public void Update()
             {
                     foreach(IUpdate i in Updates)
                             i.Update();
             }
             public void Flush()
             {
                     foreach(IUpdate i in Updates)
                             i.Flush();
             }
     };


     interface IVar<T>
     {
         T v();
     };

     // 这是缓存的变量,是无状态的。把值缓存起来可以避免重复求值
    class CachedVar<T> : IVar<T>, IUpdate
     {
         private Func<T> FuncValue;
             private T Value;
             private bool Calculated;
         public CachedVar(Func<T> funcValue)
             {
                     FuncValue = funcValue;
                     Calculated = false;
                     Manager.TheManager.Add(this);
             }
             public T v()
             {
                     if (Calculated)
                             return Value;
                     else
                             return Value = FuncValue();
             }
             public void Update(){}
             public void Flush()
             {
                     Calculated = false;
             }
     };

     // 这是有状态的变量。funcState是状态变迁的函数。
    class State<T> : IVar<T>, IUpdate
     {
         private Func<T,T> FuncState;
             private T m_Current, m_Next;
         public State(T defaultValue, Func<T,T> funcState)
             {
             m_Current = defaultValue;
                     FuncState = funcState;
                     Manager.TheManager.Add(this);
             }
             public T v()
             {
                     return m_Current;
             }
             public void Update()
             {
                     m_Next = FuncState(m_Current);
             }
             public void Flush()
             {
                     m_Current = m_Next;
             }
     }
}

C++的:

#include <list>
#include <functional>

namespace simulation
{

class IUpdate
{
public:
         virtual void Update()=0;
         virtual void Flush()=0;
};

class Manager
{
private:
         std::list<IUpdate *> m_pUpdates;
public:
         Manager()
         {
                 m_pUpdates = std::list<IUpdate *>();
         }
         void Add(IUpdate *pUpdate)
         {
                 m_pUpdates.push_back(pUpdate);
         }
         void Update()
         {
                 for(std::list<IUpdate *>::iterator i = m_pUpdates.begin(); i != m_pUpdates.end(); i++)
                         (*i)->Update();
         }
         void Flush()
         {
                 for(std::list<IUpdate *>::iterator i = m_pUpdates.begin(); i != m_pUpdates.end(); i++)
                         (*i)->Flush();
         }
};

Manager *g_pManager = new Manager;
double g_dt = 0.0;

template <class T> class IVar
{
public:
         virtual T v()=0;
};

template <class T> class CachedVar : public IVar<T>, IUpdate
{
private:
         std::tr1::function<T()> m_fValue;
         T m_Value;
         bool m_bCalculated;
public:
         CachedVar(std::tr1::function<T()> fValue)
         {
                 m_fValue = fValue;
                 m_bCalculated = false;
                 Manager->Add(this);
         }
         virtual T v()
         {
                 if (m_bCalculated)
                         return m_Value;
                 else
                         return m_Value = m_fValue();
         }
         virtual void Update(){}
         virtual void Flush()
         {
                 m_bCalculated = false;
         }
};

template <class T> class State : public IVar<T>, IUpdate
{
private:
         std::tr1::function<T(T)> m_fState;
         T m_Current, m_Next;
public:
         State(T defaultValue, std::tr1::function<T(T)> fState)
         {
                 m_fState = fState;
                 m_Current = defaultValue;
                 Manager->Add(this);
         }
         virtual T v()
         {
                 return m_Current;
         }
         virtual void Update()
         {
                 m_Next = m_fState(m_Current);
         }
         virtual void Flush()
         {
                 m_Current = m_Next;
         }
};

}

附带一个例子,太阳地球仿真(C#):

namespace SimulationCSharp
{
     public partial class Form1 : Form
     {
         bool Exit = false;

         struct Vec
         {
             public double X, Y;
             public Vec(double x, double y) { X = x; Y = y; }
             public double Norm() { return Math.Sqrt(X * X + Y * Y); }
             public static Vec operator +(Vec v1, Vec v2) { return new Vec(v1.X + v2.X, v1.Y + v2.Y); }
             public static Vec operator -(Vec v1, Vec v2) { return new Vec(v1.X - v2.X, v1.Y - v2.Y); }
             public static Vec operator *(double k, Vec v) { return new Vec(k * v.X, k * v.Y); }
             public static Vec operator *(Vec v, double k) { return new Vec(v.X * k, v.Y * k); }
             public static Vec operator /(Vec v, double k) { return new Vec(v.X / k, v.Y / k); }
         }

         public Form1()
         {
             InitializeComponent();
         }

         private double AU = 149597870691; // m
         private double Year = 3600*24*365.256363004;
         private double G = 6.67300e-11; // m3*kg-1*s-2
         private double M = 1.98892e30; // kg 太阳
        private double m = 5.9742e24; // kg 地球
        private Vec vm0 = new Vec(30287, 0); // m/s 在近日点的速度

        double TScale = 3600 * 24 * 7;
         double dt;
         long t1 = DateTime.Now.Ticks / 10000000;

         State<Vec> sM;
         State<Vec> sm;
         State<Vec> vM;
         State<Vec> vm;

         CachedVar<Vec> r_mM;
         CachedVar<Vec> r_Mm;
         CachedVar<Vec> gm;
         CachedVar<Vec> gM;

         private void Form1_Load(object sender, EventArgs e)
         {
//★★★这几行是关键★★★
             r_mM = new CachedVar<Vec>(() => sM.v() - sm.v());
             r_Mm = new CachedVar<Vec>(() => sm.v() - sM.v());
             gm = new CachedVar<Vec>(() => G * M * r_mM.v() / Math.Pow(r_mM.v().Norm(), 3));
             gM = new CachedVar<Vec>(() => G * m * r_Mm.v() / Math.Pow(r_Mm.v().Norm(), 3));

             sM = new State<Vec>(new Vec(0.0, 0.0), (x) => x + vM.v() * dt);
             sm = new State<Vec>(new Vec(0.0, 0.9832898912 * AU), (x) => x + vm.v() * dt); // 近日点
            vM = new State<Vec>(new Vec(0.0, 0.0), (x) => x + gM.v() * dt);
             vm = new State<Vec>(vm0, (x) => x + gm.v() * dt);
         }

         private void Form1_FormClosed(object sender, FormClosedEventArgs e)
         {
             Exit = true;
         }

                 private void Form1_Shown(object sender, EventArgs e)
         {
             while (Exit == false)
             {
                 long t2 = DateTime.Now.Ticks / 10000000;
                 dt = TScale * Math.Min(t2 - t1, 0.05);
                 t1 = t2;

                 Manager.TheManager.Update();

                 btnSun.Left = this.Width / 2 + (int)(100.0 * sM.v().X / AU);
                 btnSun.Top = this.Height / 2 - (int)(100.0 * sM.v().Y / AU);
                 btnEarth.Left = this.Width / 2 + (int)(100.0 * sm.v().X / AU);
                 btnEarth.Top = this.Height / 2 - (int)(100.0 * sm.v().Y / AU);

                 Manager.TheManager.Flush();

                 Application.DoEvents();
             }
         }
     }
}

最近看过此主题的会员

您需要登录后才可以回帖 登录 | 注册

‹‹
我的工具栏

关于我们|手机版|Archiver|开源计算机图形学社区(Open Source Computer Graphics Community) | OpenGPU Project | OpenGPU Forum (2007-2013)

GMT+8, 2017-11-21 06:47 , Processed in 0.050553 second(s), 11 queries .

Powered by Discuz! X2

© 2001-2011 Comsenz Inc.

回顶部