Skip to content

Search content

From F# to Gleam > 1: From FSI to Your 1st Gleam Project

3 min readFrom F# to GleamPart 1
An F# tile points to a terminal running gleam run and printing a temperature conversion.

Coming from F#, Gleam feels familiar in useful ways: immutable values, type inference, discriminated unions, and functions that compose. Unlike the move in my F# to Clojure series, we’re keeping static types.

Table of contents

On this page

A Project Instead of an FSI Session

FSI is a convenient place to evaluate an expression. Gleam’s standard toolchain doesn’t provide an equivalent interactive shell. The usual local loop is to edit a module, compile it, and run it or its tests. The interactive language tour is useful for smaller experiments.

After installing Gleam, Erlang/OTP, and Rebar3, create a project:

gleam new learning_gleam
cd learning_gleam
gleam run

The generated src/learning_gleam.gleam contains a public main function. That’s the default entry point. The compiler, formatter, dependency manager, and test command all come through the same gleam executable.

Translate One Small Program

Here’s a calculation we could put in an F# script:

let fahrenheit celsius = 32 + celsius * 9 / 5

let converted = fahrenheit 20
assert (converted = 68)
printfn "20C is %iF" convertedscratch.fsx

Replace the generated Gleam module with this:

import gleam/int
import gleam/io

fn fahrenheit(celsius: Int) -> Int {
  32 + celsius * 9 / 5
}

pub fn main() -> Nil {
  let converted = fahrenheit(20)
  assert converted == 68
  io.println("20C is " <> int.to_string(converted) <> "F")
}src/learning_gleam.gleam

Both print 20C is 68F. Gleam calls functions with parentheses and separates arguments with commas. Braces delimit a function body, whose last expression supplies its result. pub makes a definition available outside its module. Without it, fahrenheit is private.

Familiar Values, Different Spellings

IntentF#Gleam
Integer4242
Floating-point value3.53.5
Booleantrue / falseTrue / False
String concatenation"hello" + "!""hello" <> "!"
Unit value()Nil
Integer list[1; 2; 3][1, 2, 3]

Nil isn’t a nullable value. It’s Gleam’s unit value, used when a function has nothing more useful to return. io.println returns Nil.

Gleam doesn’t overload arithmetic operators. Integer addition uses +, while float addition uses +.. Float multiplication and division use *. and /.. There are no implicit conversions between Int and Float, and no built-in equivalent of F#‘s decimal.

Local let bindings are immutable. Reusing a name creates a new binding rather than changing the old value. Calculated bindings belong inside functions, while const handles module-level literals.

Try It

Add assertions for fahrenheit(0) == 32 and fahrenheit(-40) == -40, then run gleam run again. A failed assertion stops the program, so these checks make the example executable rather than relying on output comments.

These examples use Gleam 1.19.0. Parts 1 to 7 also run with gleam run --target javascript if Node.js is installed. The processes chapter needs Erlang, and the final chapter tests both targets explicitly.

Next, we’ll translate records and discriminated unions without giving up exhaustive pattern matching.

Further reading: Writing Gleam and the language tour.



Next in series
From F# to Gleam > 2: Records, Custom Types, and Pattern Matching