Froth, and this site, are pre-alpha. This site is largely OSAI-generated documentation from the Froth repo.

In Froth, a word is just a named value that can be called. There is no separate function namespace. A top-level name can hold an integer, text, cells storage, or Code. When the value is Code, calling it runs that code.

The shortest reusable definition looks like this:

to led.flash [
  led.on:;
  ms: 100;
  led.off:
]

Call it:

led.flash:

That definition creates or rebinds the top-level slot led.flash to a zero-argument Code value.

Definitions With Arguments

Use with when the code expects arguments:

to pulse with pin, wait [
  gpio.output: pin;
  gpio.high: pin;
  ms: wait;
  gpio.low: pin
]

pulse: LED_BUILTIN, 75

The parameter names are locals inside the body. They are not stack aliases; they are ordinary names with lexical scope. That is the main readability win over the old style. You can say pin and wait exactly where you need them.

to And fn

The docs use two styles:

to pulse with pin, wait [
  gpio.high: pin;
  ms: wait;
  gpio.low: pin
]

heartbeat is fn [
  led.toggle:;
  ms: 250
]

Use to name with ... [ ... ] when the definition reads like a named action. Use name is fn [ ... ] when the name feels like a value you are assigning. Both produce a top-level slot holding Code.

Anonymous Code is useful when you want to pass behavior:

twice is fn with action [
  action:;
  action:
]

beep is fn [ led.blink: 1, 30 ]
twice: beep

twice does not care where the Code came from. It receives a callable value and calls it.

Coherent Redefinition

Redefinition is one of Froth’s central promises. If code resolves a top-level name at call time, it sees the current value in that slot.

to blink.fast [
  led.blink: 1, 40
]

to signal [
  blink.fast:
]

signal:

to blink.fast [
  led.blink: 3, 90
]

signal:

signal was not rewritten. It still looks up blink.fast, and that name now holds different code.

Non-Capturing Code

Code does not capture outer locals in the current language. This is rejected:

to make-blink with wait [
  fn with pin [
    gpio.high: pin;
    ms: wait;
    gpio.low: pin
  ]
]

The inner fn tries to use wait from the outer function. Froth requires you to make that flow explicit. Usually the better definition is:

to blink.once with pin, wait [
  gpio.high: pin;
  ms: wait;
  gpio.low: pin
]

That keeps the code persistable and easy to inspect. The value you need is an argument, not hidden closure state.

Next: Locals, names, and state .