Link Search Menu Expand Document

Oters - Examples

I include in this page a few examples showcasing the Oters language with its standard library.

Carrying Values through Time

Much of the standard library is made up of stream transforming functions. That is functions that take streams as input and output another stream. However, many times we simply just want to pass a constant value. For that, we use the std::stream::const function:

use std::stream::const
use std::stream::map

let twos = map #(fn i -> i + 1) (const 1)
let name = const "John Smith"

The first two lines here just import the necessary functions.

Line 4 constructs a constant stream of 2s in a somewhat contrived manner used to illustrate the const function. The second argument of the map function the stream that we wish to map the function onto. Here, we construct a constant stream of 1s using the const function.

Line 5 similarly describes a stream of strings using const.

Combining Two Streams

use gui::widget::*
use std::stream::map
use std::stream::zip

let ui = gui::frame (0, 0)

let on_A = gui::input::is_key_down "A" << @on_A
let on_B = gui::input::is_key_down "B" << @on_B

let switch_key = fn (a, b) -> 
	if a then "A"
	else if b then "B"
  else " "

let (lab_id, lab_stream) = label ui (100, 30) (map #switch_key (zip on_A on_B)) 

let _ = gui::attach_root (ui, lab_id)

The first 3 lines here just import the necessary functions.

Line 5 creates a UI frame onto which a label will be attached.

Lines 7 and 8 create two streams of boolean values. These streams are true when the A and B keys are pressed.

Lines 10-13 define a function switch_key which takes in a tuple of booleans as input and outputs a string. We will be using this function to map the two streams defined above into a stream of strings.

Line 15 defines a label where the label’s value is given by map #(switch_key) (zip on_A on_B). The input stream zips the two “key” streams defined on lines 7 and 8 into a single stream of boolean tuples. This zipped stream is then mapped to a stream of strings via the function defined on lines 10-13. Thus, the label will display the letter “A” when the A key is pressed, and the letter “B” when the B key is pressed.

Converting Between Types

There are a few type converting functions provided by the standard library which you can find here. In the current version of Oters, these functions are implemented as imported Rust functions. This matters because they cannot be used as first class values and must be wrapped inside fn expressions:

use gui::widget::*
use std::stream::map
use std::stream::zip

let ui = gui::frame (100, 0)

let (lab_id, lab_stream) = label ui (200, 30) (map #(fn i -> std::int_to_string i) std::millis) 

let _ = gui::attach_root (ui, lab_id)

Line 7 is the only line of note here. It creates a label which as input stream takes the following expression map #(fn i -> std::int_to_string i) std::millis. This maps the millis stream, which is a stream of Unix millisecond timestamps of int type, to strings of the same values. The mapping function fn i -> std::int_to_string i is required since std::int_to_string cannot be passed as a first class value and map #std::int_to_string std::millis would result in an error.

Mutually Recursive Button

use gui::widget::*
use std::stream::map
use std::stream::fold

let ui = gui::frame (0, 0)

let (btn_id, btn_stream) = button ui (100, 75) (map #(fn i -> std::int_to_string i) presses) 
and presses = fold #(fn acc b -> if b then acc + 1 else acc) 0 btn_stream
with 0

let _ = gui::attach_root (ui, btn_id)

This program creates a button whose label is the number of times it has been clicked.

The first three lines here just import the necessary functions that will be used in the rest of the program.

Line 5 creates a UI frame onto which the button widget will be attached to. The frame is 300 pixels wide and 100 pixels tall, located at position (0, 0).

Line 7 defines the button in a mutual recursive definition with its label. The button function is from gui::widget and returns an ID and a stream of booleans bound to btn_id and btn_stream respectively. The btn_stream variable will be needed in the second part of the mutually recursive definitions. The arguments passed to button are as follows: the frame id, the size, and the stream of labels. This stream is constructed by mapping the function std::int_to_string onto the stream containing the number of presses presses defined on the following line.

Line 8 defines the stream containing the number of presses. As explained in the expressions page, this stream has its initial value defined after the with and must be bound to a single value, namely presses. The stream itself is defined using the std::fold function which applies the same function to an accumulator and then returning a stream of the accumulator’s values through time. Specifically, it increments the accumulator’s value whenever btn_stream is true, that is whenever the button is clicked.

Line 9 sets the first value of presses to be 0.

Line 11 attaches the button as the root element to the UI frame. Only the root element and its children are actually drawn on the screen, and so without this line, the button would not be drawn on the screen.