예제 #1
0
        static void Main(string[] args)
        {
            Ag.initialize();
            Aardvark.Base.Aardvark.Init();

            using (var app = new OpenGlApplication())
            {
                var win = app.CreateSimpleRenderWindow(1);

                var view        = CameraView.LookAt(new V3d(2.0, 2.0, 2.0), V3d.Zero, V3d.OOI);
                var perspective =
                    win.Sizes.Select(s => FrustumModule.perspective(60.0, 0.1, 10.0, ((float)s.X / (float)s.Y)));


                var viewTrafo = DefaultCameraController.control(win.Mouse, win.Keyboard, win.Time, view);

                var index     = new[] { 0, 1, 2, 0, 2, 3 };
                var positions = new[] { new V3f(-1, -1, 0), new V3f(1, -1, 0), new V3f(1, 1, 0), new V3f(-1, 1, 0) };

                var attributes = new SymbolDict <Array>()
                {
                    { DefaultSemantic.Positions, positions }
                };

                var quad = new IndexedGeometry(IndexedGeometryMode.TriangleList,
                                               (Array)index,
                                               attributes,
                                               new SymbolDict <Object>());

                var quadSg = quad.ToSg();

                // This is one of the hardest parts in C#. Our FShade interface is rather generic and
                // works super awesome in F#. In C# however, without proper type inference doing simple function
                // calls suddenly requires a Phd in CS. Therefore, and especially since shaders cannot be written
                // in C# anyways, write application setup and shader code in F# ;)
                // Or don't use FShade. FShade simply does not work in without functional language
                // features such as type inference and function currying.
                Func <DefaultSurfaces.Vertex, FSharpExpr <V4d> > whiteShader =
                    HighFun.ApplyArg0 <C4f, DefaultSurfaces.Vertex, FSharpExpr <V4d> >(
                        DefaultSurfaces.constantColor, C4f.White);
                Func <DefaultSurfaces.Vertex, FSharpExpr <DefaultSurfaces.Vertex> > trafo = c => DefaultSurfaces.trafo(c);

                var sg =
                    quadSg
                    .WithEffects(new[] {
                    FShadeSceneGraph.toEffect(FSharpFuncUtil.Create(trafo)),
                    FShadeSceneGraph.toEffect(FSharpFuncUtil.Create(whiteShader)),
                })
                    .ViewTrafo(viewTrafo.Select(t => t.ViewTrafo))
                    .ProjTrafo(perspective.Select(t => t.ProjTrafo()));

                var task = app.Runtime.CompileRender(win.FramebufferSignature, sg);

                win.RenderTask = DefaultOverlays.withStatistics(task);
                win.Run();
            }
        }
예제 #2
0
파일: VimTest.cs 프로젝트: sh54/VsVim
 public void LoadVimRc2()
 {
     _fileSystem.Setup(x => x.GetVimRcDirectories()).Returns(new string[] { "foo" }).Verifiable();
     _fileSystem.Setup(x => x.LoadVimRc()).Returns(FSharpOption <Tuple <string, string[]> > .None).Verifiable();
     Assert.IsFalse(_vim.LoadVimRc(FSharpFuncUtil.Create <Unit, ITextView>(_ => null)));
     Assert.AreEqual("", _settings.VimRc);
     Assert.AreEqual("foo", _settings.VimRcPaths);
     _fileSystem.Verify();
 }
예제 #3
0
        public void LoadVimRc2()
        {
            var fs = new Mock <IFileSystem>(MockBehavior.Strict);

            fs.Setup(x => x.GetVimRcDirectories()).Returns(new string[] { "foo" }).Verifiable();
            fs.Setup(x => x.LoadVimRc()).Returns(FSharpOption <Tuple <string, string[]> > .None).Verifiable();
            Assert.IsFalse(_vim.LoadVimRc(fs.Object, FSharpFuncUtil.Create <Unit, ITextView>(_ => null)));
            Assert.AreEqual("", _settings.VimRc);
            Assert.AreEqual("foo", _settings.VimRcPaths);
            fs.Verify();
        }
예제 #4
0
        static void Main(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            var inputModeChanger = new WinFormsInputModeChanger();
            var bus  = Init.buildVoid(inputModeChanger, Options.parse(args));
            var view = new MainForm(bus, inputModeChanger);

            bus.subscribe(FSharpFuncUtil.Create <CoreEvent, Message>(view.HandleEvent));
            bus.subscribe(FSharpFuncUtil.Create <VMEvent, Message>(view.HandleViewModelEvent));
            Init.launchVoid(bus);
            Application.Run(view);
        }
예제 #5
0
        static void Main(string[] args)
        {
            #region Basic Mod usage

            // Create a modref cell. can be changed via side effects
            var input = new ChangeableValue <int>(10);

            var output = input.Map(x => x * 2);

            Console.WriteLine($"output was: {output}");
            // Prints: output was Aardvark.Base.Incremental.ModModule+MapMod`2[System.Int32,System.Int32]
            // not what we expected. Since mods are lazy and tostring does not force them we need
            // to pull the value out of it.

            Console.WriteLine($"output was: {output.GetValue()}"); // F# equivalent: Mod.force : aval<'a> -> 'a
            // output was: 20

            using (Adaptive.Transact)
            {
                input.Value = 20;
            }

            Console.WriteLine($"output was: {output.GetValue()}");
            // output was: 40

            // semantically, output now dependens on input declaratively.
            // the dependency graph looks like:
            //
            //       (x) => x * 2
            // input ----------------> output
            // mods are nodes, and the edges are annotated with transition functions.

            // Users of Rx might see the pattern. outputs is an observer, while input is observable.
            // so the systems are equivalent ?! but mod must be better - otherwise this tutorial is useless right?

            #endregion

            #region Obserable semantics

            // A modref could be an observable which never ends and has an initial value.
            var inputObs = new Subject <int>();
            inputObs.OnNext(10);
            var outputObs = inputObs.Select(x => x * 2);

            var globalStore         = 0;
            var sideEffectToObserve = outputObs.Subscribe(x => globalStore = x);

            Console.WriteLine($"outputObs was: {globalStore}");
            // outputObs was: 0
            // unexpected? no. this is due to subscription semantics.
            // Note: ReplaySubject instead of subject has right semantics although i have doubts about memory leaks.

            inputObs.OnNext(10);
            Console.WriteLine($"outputObs was: {globalStore}");
            // outputObs was: 20

            inputObs.OnNext(20);
            Console.WriteLine($"outputObs was: {globalStore}");
            // outputObs was: 40


            // what happens if we have data flow graphs with sinks (2 ingoing edges conceptually)

            var inputA = new Subject <int>();
            var inputB = new Subject <int>();

            var reexCount = 0;

            inputA.Merge(inputB).Subscribe(x =>
            {
                reexCount++;
                Console.WriteLine($"a+b was: {x}");
            });

            inputA.OnNext(1);
            inputB.OnNext(2);
            Console.WriteLine($"reexCount was: {reexCount}");
            // reexCount was: 2

            // did you expect 2? of course. this is the semantics of merge.

            // what iff we only want to have a batch change, say, change 2 inputs simultationusly?
            // then we need different semantics.
            var inputA3 = new Subject <int>();
            var inputB3 = new Subject <int>();

            reexCount = 0;
            inputA3.SelectMany(a =>
                               inputB3.Select(b =>
            {
                reexCount++;
                return(a + b);
            }
                                              )
                               ).Subscribe(r =>
                                           Console.WriteLine($"result was: {r} reexCount was: {reexCount}")
                                           );

            inputA3.OnNext(1);
            inputB3.OnNext(2);
            // result was: 3 reexCount was: 1

            // If we switch to replay subject we get 2 again...
            var inputA2 = new ReplaySubject <int>();
            var inputB2 = new ReplaySubject <int>();

            reexCount = 0;
            inputA2.SelectMany(a =>
                               inputB2.Select(b =>
            {
                reexCount++;
                return(a + b);
            }
                                              )
                               ).Subscribe(r =>
                                           Console.WriteLine($"result was: {r} reexCount was: {reexCount}")
                                           );

            inputA2.OnNext(1);
            inputB2.OnNext(2);
            // result was: 3 reexCount was: 2

            // Let us see how this looks like in Mod:
            reexCount = 0;
            var inputAM = new ChangeableValue <int>(1);
            var inputBM = new ChangeableValue <int>(2);
            var aPlusB  = inputAM.Map(inputBM,
                                      (a, b) => {
                reexCount++;
                return(a + b);
            });

            Console.WriteLine($"mod,a+b was: {aPlusB.GetValue()}, reexCount: {reexCount}");
            // mod,a+b was: 3, reexCount: 1

            // special note: Select2 was not defined at the time or writing of this tutorial, but
            // it is available in F#. How could we access the F# verion?
            var aPlusB2 = FSharp.Data.Adaptive.AValModule.map2(FSharpFuncUtil.Create <int, int, int>((a, b) => a + b), inputAM, inputBM);
            // steps required:
            // (1) F# map2 is defined in Mod module. usage Mod.map2 (+) a b
            // so we need this map module. by convention, modules with colliding type names
            // are exported with the module suffix. so the function lives in ModModule.
            // (2) our f# function wants a f# function and not an instance of type System.Func. use a conversion
            // (3) C# has no real type inference, so most of the time you'll need to annotate stuff.
            // that is - we just used a f# function with no c# friendly interface in c#.
            Console.WriteLine($"mod,a+b was: {aPlusB2.GetValue()}, reexCount: {reexCount}");

            reexCount = 0;
            using (Adaptive.Transact)
            {
                inputAM.Value = 20;
                inputBM.Value = 30;
            }

            Console.WriteLine($"mod,a+b was: {aPlusB.GetValue()}, reexCount: {reexCount}");
            // mod,a+b was: 50, reexCount: 1

            // so we have batch changes in the mod system. but this is cheating, right?
            // because we used an optimized combinator which does this, right?
            // we can do a low level implementation instead.

            var aPlusBBind = inputAM.Bind(a => inputBM.Map(b =>
            {
                reexCount++;
                return(a + b);
            }));

            reexCount = 0;
            using (Adaptive.Transact)
            {
                inputAM.Value = 20;
                inputBM.Value = 30;
            }

            Console.WriteLine($"modbind,a+b was: {aPlusBBind.GetValue()}, reexCount: {reexCount}");
            // modbind,a+b was: 50, reexCount: 1
            // interesting. also here we have tight reexecution count.

            reexCount = 0;
            using (Adaptive.Transact)
            {
                inputAM.Value = 20;
                inputBM.Value = 30;
            }

            Console.WriteLine($"modbind2,a+b was: {aPlusBBind.GetValue()}, reexCount: {reexCount}");
            // modbind2,a + b was: 50, reexCount:0
            // aha - we have reexCount=0 because the change was a pseudo change (values changed to old values)

            /*
             * So what is the result of this analysis? Rx has precise semantics. You get what you want. But
             * you need to know how you want it and there are many solutions.
             * So Mod is the same as observable, but can do less because we do not have precise control about
             * reexecution semantics (although semantics seems to be nice, right)?
             */

            // One could use the mod system as strange implementation of observable of course.
            var inputEvil  = new ChangeableValue <int>(10);
            var outputEvil = new ChangeableValue <int>(0);



            var sub = inputEvil.AddCallback(i =>
            {
                using (Adaptive.Transact)
                {
                    outputEvil.Value = i * 2;
                }
            });

            using (Adaptive.Transact)
            {
                inputEvil.Value = 20;
            }
            Console.WriteLine($"evilCallback: {outputEvil.GetValue()}");
            // evilCallback: 40

            /* so this works. but this is evil.
             * /* this code has no dependency graph. all is modelled via side effects.
             * /* The following list sponsored by gh gives some reasons against callbacks:
             * 1) The Mod-system is capable of handling those callbacks but their cost is massive compared to Rx
             * 2) Callbacks tend to keep their closure alive(causing memory leaks)
             * 3) Callbacks are hard to debug
             * 4) Eager evaluation wastes time (by design and especially when using the mod-system)
             * 5) Concurrency is not controlled in any way
             * 6) Callers of transact suddenly block until their callbacks finish(deadlock scenarios etc.)
             * 7) Rx was already invented (so why exploit our system to simulate it) */

            #endregion

            /*
             * So finally, the answer is: NO
             * Rx and Mod is something completly different.
             * - Mod is lazy / Obs pushes values to their subscribers immediately
             * - Mods have batch changes intrinsic to the system / in Obs semantics depends on combinators
             * - Mods build dependency graphs and try to reduce recomputation overhead / Obs don't care about algorithmic complexity, Obs cannot be used to implement adaptive data structures
             * - Mods have on goal: make the outputs consistent iff they are demaned. / Obs populates all values according to the combinators used (e.g. merge)
             */

            // As a result there are many things which do not fit to observables, others do not fit to mods.

            // Given this list, Mods are particularly not immediately usable for tracking changes manually.
            var resendOverNetwork = new ChangeableValue <bool>(false);
            inputEvil.AddCallback(s =>
            {
                using (Adaptive.Transact)
                {
                    resendOverNetwork.Value = true;
                }
            }
                                  );
            resendOverNetwork.AddCallback(_ =>
            {
                inputEvil.GetValue().ToString(); // send new contents of inputEvil
            });
            // UnsafeRegisterCallbackNoGcRoot is a hack in the system to allow unproblematic side effects
            // to be coupled with reecution. The exeuction of order of callbacks, especially callbacks
            // which run callbacks via transactions is highly unspecified. In fact
            // UnsafeRegisterCallbackNoGcRoot has no defined semantics.

            // One little note: (in the current implementation) all callbacks are executed eventuallly, but maybe to often.
            // This is very comparable to LINQ mixed with side effects. LINQ has lazy evaluation and using
            // side effects inside is just nonesense. Fortunately LINQ has no public cheat API --- one cannot
            // simply "side-effect" elements into an existing enumerable sequence
            // (ok we can but peoply luckily rarely mix side effects with linq because meijer said it is evil [1]).
            // [1] https://www.youtube.com/watch?v=UuamC0T3hv8
            // Of course we could restrict the mod API (by removing callbacks), but
            // we still wanted ways to do unsafe stuff (in less than 0.01% of the code).
            // At this point we shall mention that the complete rendering backend works without callbacks,
            // but rendering things could be as well considered as rather imperative problem.
            // If you really want to attach callbacks to some mod, maybe either:
            // (1) the problem does not fit the declarative incremental computation modlel
            // (2) the problem fits, but some parts of the current solution are not delcarative (either because of (1), because of hacks or other non-declarative parts)

            /* You know might think: "Why all this complexity. Why not just use Observables where
             * appropriate and ad hoc techniques when they not work as nice as they should. I pretty
             * lived quite good the last years without a mod system and this stuff".
             * Cases in which the mod system is a good fit can greatly benefit from the usage of mods.
             * The changes are not local, but having a mod system at hand completely changes the way
             * on can structure programs. In fact, i think programming with mods is a completely different
             * paradigm. So Take your time and help us making the libraries better.
             */
        }