Variables and Let Expressions
In NumFu, variables can be created in two ways:
- Using
let
bindings within
, which create local scopes for values - Using top-level
let
statements, which define program-wide variables
This provides both functional scoping and practical module-level state management.
Let Bindings
Let bindings create local scopes and return values. The basic syntax is let name = value in expression
:
let x = 42 in x // 42
let name = "NumFu" in name // "NumFu"
let flag = true in flag // true
The variable x
is only available within the in
part of the expression.
Using Variables in Calculations
Variables become powerful when used in calculations:
let radius = 5 in pi * radius^2 // Circle area: ~78.54
let price = 100 in
let tax = 0.08 in
price * (1 + tax) // Price with tax: 108
Let Expressions Return Values
Remember that let
expressions return the value of the in
part:
let result = let x = 10
in x * 2
in result + 5 // 25
Multiple Variable Bindings
Comma-Separated Bindings
You can define multiple variables in a single let
expression. All variables defined in the same let
are available throughout the in
body:
let x = 3, y = 4 in x^2 + y^2 // 25
let first = "Hello", second = "World" in
first + " " + second // "Hello World"
let a = 1, b = 2, c = 3 in a + b + c // 6
Mutual Reference
Variables in the same let
cannot reference each other:
let x = y + 1, y = 5 in x
// NameError: 'y' is not defined in the current scope
Variable Scoping
Lexical Scoping
NumFu uses lexical (static) scoping - variables are accessible where they're defined:
let outer = 10 in
let inner = 20 in
outer + inner // 30 - both variables accessible
Nested Scoping
Inner scopes have access to outer scopes:
let a = 1 in
let b = 2 in
let c = 3 in
a + b + c // 6
Scope Boundaries
Variables are only accessible within their scope:
let x = 10 in x + 5 // 15
x // NameError: 'x' is not defined in the current scope
Variable Shadowing
Inner Variables Shadow Outer Ones
When you define a variable with the same name in an inner scope, it "shadows" the outer one:
let x = 10 in
let x = 20 in
x // 20 (inner x)
Original Values Preserved
The outer variable is unchanged by shadowing:
let x = 10 in
let result = let x = 20 in x in
[x, result] // [10, 20]
Practical Shadowing
Shadowing is useful for transforming values step by step:
import trim, toLowerCase, replace from "std"
let data = " Hello World " in
let data = trim(data) in // Remove whitespace
let data = toLowerCase(data) in // Convert to lowercase
let data = replace(data, " ", "_") in // Replace spaces
data // "hello_world"
Let Statements
Let statements define variables that are available throughout your program:
import * from "io"
let PI = 3.14159
let greeting = "Welcome to NumFu!"
// These are available in all expressions below
println(greeting)
print("pi^2 = ")
PI^2
Let statements must be at the module (file) level and can only assign one variable at a time:
let x = 5 in
let INVALID = 10
// SyntaxError: Missing 'in' — bare 'let' allowed only at top level
let a = 1, b = 2
// SyntaxError: Cannot assign multiple identifiers here
Deleting Variables
To remove a variable which was previously declared using a let statement, use the del
statement:
let temp = "temporary"
// ... use temp ...
del temp // Variable is no longer available
Like let statements, del
statements can only be used at the module (file) level.
Variable Naming
The keywords and special symbols listed below cannot be used as variable names or function parameters. The parser will throw an error if you try to use them.
let
, in
, if
, then
, else
, del
,import
, export
, from
, true
, false
, $
, _
Examples
Basic Variable Usage
import pi from "math"
// Calculate the volume of a cylinder
let radius = 3, height = 10 in
let baseArea = pi * radius^2 in
baseArea * height // ~282.74
// Convert temperature scales
let celsius = 25 in
let fahrenheit = celsius * 9/5 + 32 in
let kelvin = celsius + 273.15 in
[celsius, fahrenheit, kelvin] // [25, 77, 298.15]
Scoping
let outer = "outer" in
let inner = "inner" in
let result = outer + " and " + inner in
result // "outer and inner"
let x = 1 in
let x = x + 1 in
let x = x * 2 in
x // 4
Multiple Bindings
import sqrt from "math"
let point = [3, 4] in
let x = point[0], y = point[1] in
sqrt(x^2 + y^2)
// Distance from origin: 5
// Calculate a student's final score
let homeworkAvg = 85, testAvg = 92, finalExam = 88 in
let homeworkWeight = 0.3, testWeight = 0.4, finalWeight = 0.3 in
homeworkAvg * homeworkWeight +
testAvg * testWeight +
finalExam * finalWeight
// 88.7
Intermediate Calculations
Quadratic formula: x = (-b ± √(b²-4ac)) / 2a
import sqrt from "math"
let a = 1, b = -5, c = 6 in
let discriminant = b^2 - 4*a*c in
let sqrt_discriminant = sqrt(discriminant) in
let x1 = (-b + sqrt_discriminant) / (2*a) in
let x2 = (-b - sqrt_discriminant) / (2*a) in
[x1, x2] // [3, 2]