From 2c01d4daeff989a556083d26b7c6e5cf7f89b472 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Sat, 5 Feb 2022 17:41:36 -0500 Subject: Prefix old post file names with dates. --- posts/2014-03-09-guile-2d-frp.md | 62 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 posts/2014-03-09-guile-2d-frp.md (limited to 'posts/2014-03-09-guile-2d-frp.md') diff --git a/posts/2014-03-09-guile-2d-frp.md b/posts/2014-03-09-guile-2d-frp.md new file mode 100644 index 0000000..1970e73 --- /dev/null +++ b/posts/2014-03-09-guile-2d-frp.md @@ -0,0 +1,62 @@ +title: Functional Reactive Programming in Scheme with guile-2d +date: 2014-03-09 21:00:00 +tags: foss, gnu, guile, scheme, gamedev, wsu +summary: Introduction to FRP in Scheme with guile-2d +--- + +Last month, the [GNU Guile](https://gnu.org/s/guile) project +celebrated the 3rd anniversary of its 2.0 release with a hacker +[potluck](http://savannah.gnu.org/forum/forum.php?forum_id=7887). +Guilers were encouraged to bring a tasty hack to the mailing list to +share with everyone. My dish was a simple +[functional reactive programming](https://en.wikipedia.org/wiki/Functional_reactive_programming) +library. + +Functional reactive programming (FRP) provides a way to describe +time-varying values and their relationships using a functional and +declarative programming style. To understand what this means, let’s +investigate a typical variable definition in Scheme. The expression +`(define c (+ a b))` defines the variable `c` to be the sum of +variables `a` and `b` at the time of evaluation. If `a` or `b` is +assigned a new value, `c` remains the same. However, for applications +that deal with state that transforms over time, it would be convenient +if we could define `c` to react to changes in `a` and `b` by +recomputing the sum. Contrast this approach with the more traditional +style of modeling dynamic state via events and callbacks. A lot of +programmers, myself included, have written code with so many callbacks +that the resulting program is unmaintainable spaghetti code. Callback +hell is real, but if you accept FRP into your heart then you will be +saved! + +By now you’re probably wondering: “What the hell does all this mean?” +So, here’s a real-world example of guile-2d’s FRP API: + +```scheme +(define-signal position + (signal-fold v+ (vector2 320 240) + (signal-map (lambda (v) + (vscale v 4)) + (signal-sample game-agenda 1 key-arrows)))) +``` + +In guile-2d, time-varying values are called “signals”. The above +signal describes a relationship between the arrow keys on the keyboard +and the position of the player. `signal-sample` is used to trigger a +signal update upon every game tick that provides the current state of +the arrow keys. `key-arrows` is a vector2 that maps to the current +state of the arrow keys, allowing for 8 direction movement. This +vector2 is then scaled 4x to make the player move faster. Finally, +the scaled vector is added to the previous player position via +`signal-fold`. The player’s position is at `(320, 240)` initially. +As you can see, there are no callbacks and explicit mutation needed. +Those details have been abstracted away, freeing the programmer to +focus on more important things. + +I think it’s helpful to see FRP in action to really appreciate the +magic. So, check out this screencast! + +![](/videos/guile-2d-frp-demo.webm) + +To see all of the juicy implementation details, check out the +[git repository](https://gitorious.org/sly/sly/source/sly/signal.scm). +Thanks for following along! -- cgit v1.2.3