Grain

A modern web staple.

Grain is a language built for the modern web by leveraging the brilliant work done by the WebAssembly project.

All of the types.
None of the burden.

No runtime type errors, ever. Every bit of Grain you write is thoroughly sifted for type errors, with no need for any type annotations.

Seriously functional.
Respectably pragmatic.

Grain is geared towards functional programming, but understands the web isn't as pure as we would like it to be. Easily write what's appropriate for the scenario.

Language Constructs


Bindings

These work just as you'd expect of any reasonable language.


let someNumber = 5
let someString = "A collection of characters"

Functions

Lambdas are king (and by that we mean first-class) in Grain. Here we show the function 'add2' being closed over inside the 'add3' function.


# A simple function that adds two numbers
let add2 = (x, y) => x + y
add2(3, 4)

# A function that adds three numbers with intermediate steps
let add3 = (x, y, z) => {
  let firstSum = add2(x, y)
  let secondSum = add2(firstSum, z)
  secondSum
}
add3(5, 6, 7)

Recursion

No functional language is complete without recursion (or in this case, mutual recursion).


let rec isEven = (n) =>
  if (n <= 1) {
    n == 0
  } else {
    isOdd(n - 1)
  }
and isOdd = (n) =>
  if (n <= 1) {
    n == 1
  } else {
    isEven(n - 1)
  }
isOdd(999)

Tuples

Sometimes it's best to work as a pair.

let tup = (4, 2)
let (first, second) = tup
first + second

Mutation

If that's your kind of thing. Of course, we'd prefer to do everything functionally if possible, but it should still be easy to work this way if necessary.


let variable = box 5
let mutateSomeThings = () => {
  if (unbox variable > 2) {
    variable := (unbox variable) - 2
  } else {
    variable := (unbox variable) + 2
  }
}
mutateSomeThings()
unbox variable # 3 resides in this box

DOM Manipulation

DOM nodes are primitives in Grain. Traditional DOM queries and node operations are available.


let div1 = DOM.query("#div1")
let div2 = DOM.query("#div2")
let div3 = DOM.query("#div3")
DOM.setText(div1, "I'm just a div.")
DOM.setText(div2, "Sitting here on wasm hill.")
DOM.dangerouslySetInnerHTML(div3, "<i>[[grain]]</i>")

DOM Interaction

Native Grain functions can be bound as callbacks to native DOM events. This example updates a counter whenever the button is clicked.

let counter = box 0
let button = DOM.query("#button1")
let view = DOM.query("#div1")
let handleEvent = () => {
  counter := (unbox counter) + 1
  DOM.setText(view, toString(unbox counter))
}
DOM.addEventListener(button, "click", handleEvent)

...and so much more.

Check out the documentation to learn more, or get started now. If you're interested in getting involved in the development of the language, check out the Grain source.