中文第一计算机图形学社区OpenGPU 版权所有2007-2018

 找回密码
 注册

扫一扫,访问微社区

搜索
查看: 2043|回复: 4

使用simulation模板库进行纯函数式编程

[复制链接]
发表于 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();
             }
         }
     }
}
 楼主| 发表于 2018-1-30 22:03:19 | 显示全部楼层
//F# の詳細 (http://fsharp.net)

namespace Simulation

    open System
    open System.Collections.Generic

    type IUpdate = interface
        abstract Update : unit -> unit
        abstract Flush : unit -> unit
    end

    module Manager =
        let Updates = new LinkedList<IUpdate>()
        let Add (update : IUpdate) = ignore (Updates.AddLast update)
        let Update () = for i in Updates do i.Update()
        let Flush () = for i in Updates do i.Flush()

    type IVar<'T> = interface
        abstract v : unit -> 'T
    end

    type CachedVar<'T> = class
        interface IVar<'T> with
            member x.v () =
                if x.Calculated then
                    x.Value
                else
                    x.Value <- x.FuncValue.Invoke ()
                    x.Value
        end
        interface IUpdate with
            member x.Update () = ()
            member x.Flush () = x.Calculated <- false
        end
        val mutable FuncValue : Func<'T>
        val mutable Value : 'T
        val mutable Calculated : bool
        member x.Init (funcValue : Func<'T>) =
            x.FuncValue <- funcValue
            x.Calculated <- false
            Manager.Add x
    end

    type State<'T> = class
        interface IVar<'T> with
            member x.v () = x.Current
        end
        interface IUpdate with
            member x.Update () = x.Next <- x.FuncState.Invoke(x.Current)
            member x.Flush () = x.Current <- x.Next
        end
        val mutable FuncState : Func<'T,'T>
        val mutable Current : 'T
        val mutable Next : 'T
        member x.Init (defaultValue : 'T, funcState : Func<'T,'T>) =
            x.Current <- defaultValue
            x.FuncState <- funcState
            Manager.Add x
    end
 楼主| 发表于 2018-3-27 14:55:09 来自手机 | 显示全部楼层
takaku1024 发表于 2018-1-30 22:03
//F# の詳細 (http://fsharp.net)

namespace Simulation

//F# の詳細 (http://fsharp.net)

namespace Simulation

    open System
    open System.Collections.Generic

    type IUpdate = interface
        abstract Update : unit -> unit
        abstract Flush : unit -> unit
    end

    module Manager =
        let Updates = new LinkedList<IU
来自: 微社区
 楼主| 发表于 2018-3-31 18:25:54 来自手机 | 显示全部楼层
修正了 F# 版的,在这里(8楼):
http://bbs.gameres.com/forum.php?mod=viewthread&tid=663392&pid=2143844&page=1&extra=&mobile=no
来自: 微社区
 楼主| 发表于 2018-10-21 18:05:31 | 显示全部楼层
修正了 F# 版的,在这里
namespace Simulation

    open System
    open System.Collections.Generic

    type IUpdate = interface
        abstract Update : unit -> unit
        abstract Flush : unit -> unit
    end

    module Manager =
        let Updates = new LinkedList<IUpdate>()
        let Add (update : IUpdate) = ignore (Updates.AddLast update)
        let Update () = for i in Updates do i.Update()
        let Flush () = for i in Updates do i.Flush()

    type IVar<'T> = interface
        abstract v : unit -> 'T
    end

    type CachedVar<'T> = class
        interface IVar<'T> with
            member x.v () =
                if x.Calculated then
                    x.Value
                else
                    x.Value <- x.FuncValue.Invoke ()
                    x.Value
        end
        interface IUpdate with
            member x.Update () = ()
            member x.Flush () = x.Calculated <- false
        end
        val mutable FuncValue : Func<'T>
        [<DefaultValue>]
        val mutable Value : 'T
        val mutable Calculated : bool
        new (funcValue : Func<'T>) as x =
            {
                FuncValue = funcValue;
                Calculated = false
            }
            then
                Manager.Add x
    end

    type State<'T> = class
        interface IVar<'T> with
            member x.v () = x.Current
        end
        interface IUpdate with
            member x.Update () = x.Next <- x.FuncState.Invoke(x.Current)
            member x.Flush () = x.Current <- x.Next
        end
        val mutable FuncState : Func<'T,'T>
        val mutable Current : 'T
        [<DefaultValue>]
        val mutable Next : 'T
        new (defaultValue : 'T, funcState : Func<'T,'T>) as x =
            {
                Current = defaultValue;
                FuncState = funcState
            }
            then
                Manager.Add x
    end
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|关于我们|小黑屋|Archiver|手机版|中文第一计算机图形学社区OpenGPU

GMT+8, 2019-1-22 09:12 , Processed in 0.075186 second(s), 22 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表