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 string
s 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.