Expressions and Values
GoLisp has no statements. Everything is an expression that produces a value.
S-Expressions
Code is data. A function call is a list where the first element is the function and the rest are arguments:
(+ 1 2) ; 3
(* 3 (+ 1 2)) ; 9
(str "hello" " " "world") ; "hello world"
This uniform syntax means there's no distinction between operators and functions — + is just a function that takes numbers.
Primitive Types
42 ; int
3.14 ; float64
"hello" ; string
true ; bool
false ; bool
nil ; zero value / absence
Numeric literals are int by default. Use float64 to convert:
(float64 42) ; 42.0
(int 3.9) ; 3
Arithmetic on any-typed values (such as map lookups) coerces numbers automatically, so these explicit conversions are needed only when you want to pin a type — see Numeric Auto-Coercion.
Let Bindings
let binds names to values within a scope:
(let [x 10
y 20]
(+ x y)) ; 30
Bindings can include an explicit type annotation:
(let [x int 10
s string "hello"]
(println s x))
Bindings are sequential — each one can reference the previous:
(let [x 5
y (* x 2)
z (+ x y)]
z) ; 15
Top-Level Definitions
def binds a value at the top level of a namespace:
(def pi float64 3.14159)
(def greeting "Hello, GoLisp!")
(def primes []int [2 3 5 7 11 13])
Keywords
Keywords are self-evaluating identifiers that start with :. They're used as map keys and field names:
:name
:user-id
:enabled?
Keywords can look up values in maps:
(let [m {:name "Alice" :age 30}]
(:name m)) ; "Alice"
Truthiness
Only two values are falsy: nil and false. Everything else is truthy — including 0, empty strings, and empty collections.
(if 0 "truthy" "falsy") ; "truthy"
(if "" "truthy" "falsy") ; "truthy"
(if nil "truthy" "falsy") ; "falsy"
(if false "truthy" "falsy") ; "falsy"
This means you can use map lookups directly as conditions without (not= result nil) boilerplate:
(if (get m "key") "found" "missing")
Equality
= compares by value, not identity. Collections are equal when their contents
are equal, and numbers compare across types, so an int and an equal float64
are =:
(= [1 2 3] [1 2 3]) ; true
(= {:a 1} {:a 1}) ; true
(= 1 1.0) ; true
(= 1 "1") ; false (different types of value)
not= is its negation. This matters when comparing values that flow through
any-typed maps or boxed arithmetic — a computed int64 still compares equal to
an int literal.
Comments
Single-line comments start with ;:
; This is a comment
(+ 1 2) ; inline comment
Three semicolons mark a docstring — shown by glisp doc:
;;; Returns the sum of a and b.
(defn add [a int b int] -> int (+ a b))