try Scheme instead of JavaScript for UI
Tags: tutorial, javascript, functional, webdev
Published: 2020-02-20 17:23:29

_In this tutorial we'll try create animation
[LIKE THIS](https://codeabbey.github.io/js-things/bunny/index.html) (Bunny image bouncing inside rectangular DIV) - using funny language Scheme instead of JavaScript._

## Why trying Scheme?

Besides being fun and with curious syntax, it greatly influences your coding style. It is **very hard to write bad code** in Scheme/LISP because
you'll get lost in the heaps of parentheses. So it makes you arranging code in small and clever functions (we call it "decomposition").

Also, if you go in depth, it teaches a lot about functional programming, especially with its list data types.

## What is Scheme

Scheme is functional language with **very** simple syntax. It is one of main branches of LISP - which is the oldest language still being used widely enough. (Fortran is older, but not used that much nowadays) If you heard of `Clojure`, `Guile`, `Common Lisp` - you know they are variants.

It looks like this:

```scheme
(alert (+ 5 8))
```

Note two things:

- all language constructions are simply made of list elements inside parentheses, or round brackets, i.e. `( ... )`
- all function names and operators are put immediately after opening bracket

So our example simply calculates sum of `5` and `8` and shows it with browser alert box (it is for browser version, of course)

We will use Scheme implemented in JS, called [BiwaScheme](https://www.biwascheme.org/) - as we want it for UI tasks. You can try the expression above in the interpreter on this page.

---

## Let's start - Page Setup

I'll do everything in single html file, for clarity - though you can split it later, of course. Let's make `<div>` with `<img>` of the bunny inside:

```html
<div id="field">
    <h1>Heeey, I'm Bouncing Bunny!</h1>
    <img id="bunny" src="https://codeabbey.github.io/js-things/bunny/bunny2.png"/>
</div>
```
And add some coloring and form (you may see, final demo fits any window, but for now let's use fixed size of the `DIV`):

```html
<style>
    body {
        background: gray;
        text-align: center;
    }
    #field {
        background: cyan;
        margin: 0px auto;
        position: relative;
        width: 640px;
        height: 480px;
    }
    #bunny {
        position: absolute;
        height: 100px;
    }
</style>
```

At last let's add some stub for script with `Scheme`. You see, we use `biwascheme.js` (release from the site mentioned above) in `src` attribute and the code itself inside tags (which is a bit unorthodox) - but that's not the only method. This code will find `H1` element and set its color to `red`, just as we can do it with jQuery:

```html
<script src="https://codeabbey.github.io/js-things/biwascheme.js">
(set-style! (get-elem "h1") "color" "red")
</script>
```
Put all three snippets into file and check if it works.  
You should see [**something like this**](https://codeabbey.github.io/js-things/bunny/step1.html).

---

## Variables and Bunny positioning

Global variables are not very good in functional code, but the task of animation is also not very "functional" one, so let's add `X` and `Y` to mark current position of the bunny. This and all the following should be put inside `<script>` stub we created above:

```scheme
(define x 0)
(define y 0)
```
Now we also would like to have some auxiliary variables - to hold `field` and `bunny` DOM objects - and also for sizes of the field (while sizes of bunny are not calculated before image is loaded, we'll work around this). For such things we have several simple functions which are not in standard `Scheme`, but were added in `BiwaScheme` for interoperability with JavaScript:

```scheme
(define field (getelem "#field"))
(define fieldW (element-width field))
(define fieldH (element-height field))

(define bunny (getelem "#bunny"))
```

At last let's add function for setting coordinates of the Bunny - and add test-call to it, to check it works. It works just by assigning `top` and `left` styles of the `bunny` element we got above:

```scheme
(define (bunnyMove left top)
    (set-style! bunny "left" left)
    (set-style! bunny "top" top))

(bunnyMove 50 50)

```
This code doesn't have a lot of observable changes compared to previous step - but the bunny should be off the center line to prove coordinates and moving works really.  
[**See here how it should look, please**](https://codeabbey.github.io/js-things/bunny/step2.html).

---

## Timer and Movement

So now we need to setup something like `setInterval(...)` to change coordinates over time and update bunny position. Final example uses `requestAnimationFrame` instead, but let's go on with timer now for simplicity. `BiwaScheme` includes simple analog of **setInterval**:

```scheme
(set-timer! updatePosition 0.05)
```

Here `set-timer!` specifies delay in seconds (so it is 0.05, i.e. 50ms - 20 frames per second). We are going to call `updatePosition` function on timer ticks. But we need to add it of course:

```scheme
(define updatePosition
    (lambda ()
        (set! x (+ x 1))
        (set! y (+ y 1))
        (bunnyMove x y)))
```

Here we see that syntax for defining function is the same as for variable - we just assign lambda-function (with no arguments) to the `updatePosition` variable. Scheme also has simplified syntax for the same, as you can see in `bunnyMove` definition.

Add these snippets to the end of your script and see - bunny should start moving, though ignoring bounds of the field.  
[**Look here for example, please...**](https://codeabbey.github.io/js-things/bunny/step3.html)

---

## Regard Borders and Speed-up

To make Bunny respect borders of the field, we'll need to teach it changing direction. For this we should add something instead of `1` to its
coordinates. Let's create variables for vertical and horizontal speed, and use it in `updatePosition`:

```scheme
; put this below x, y definition
(define vx 2)
(define vy 2)

; and later...
(define (updatePosition)
    (set! x (+ x vx))
    (set! y (+ y vy))
    (bunnyMove x y))
```
Now we just need to check inside the `updatePosition` for following conditions:

- if bunny reaches bottom, i.e. `y >= field_height - bunny_height` - then switch `vy` to negative
- if bunny reaches top, i.e. `y <= 0` - then switch `vy` back to positive
- make two similar checks for `x` coordinate

```scheme
(define (updatePosition)
    (if (>= y (- fieldH (element-height bunny))) (set! vy -2))
    (if (>= x (- fieldW (element-width bunny))) (set! vx -2))
    (if (<= y 0) (set! vy 2))
    (if (<= x 0) (set! vx 2))
    (set! x (+ x vx))
    (set! y (+ y vy))
    (bunnyMove x y))
```
_Note that we call function to calculate bunny size every time. This is workaround because we couldn't get it until bunny image is loaded. Of course it could be done in more clever way, but let's keep it simple._

Surprisingly, that's all! Now bunny should bounce of all 4 borders.  
[**Look how it works in the last example**](https://codeabbey.github.io/js-things/bunny/step4.html)

---

## Conclusion

So we see, `Scheme` looks not too bad when dealing with `JavaScript` tasks! I can't tell for sure how good it is with larger programs - I just decided to try it myself.

The "final" version of the code, linked at the beginning of this post, is slightly advanced - adapting to various screen sizes and using `requestAnimationFrame` and time deltas. You may study it, but probably it is too obvious and you even know how to do this better.

**I hope that even if you won't write much in LISP/Scheme - you still can try it for amusement, and to learn a bit more about different programming languages!**

Thanks for reading that far and Happy Coding!