Skip to content

Data Types

Sema has a rich set of built-in data types covering numbers, text, collections, and LLM primitives.

Type Table

TypeSyntaxExamples
Integerdigits42, -7, 0
Floatdigits with .3.14, -0.5, 0.001
Stringdouble-quoted"hello", "line\nbreak", "\x1B;"
F-Stringf"...${expr}..."f"Hello ${name}", f"${(+ 1 2)}"
Boolean#t / #f#t, #f
Nilnilnil
Symbolbare identifierfoo, my-var, +
Keywordcolon-prefixed:name, :type, :ok
Character#\ prefix#\a, #\space, #\newline
Listparenthesized(1 2 3), (+ a b)
Vectorbracketed[1 2 3], ["a" "b"]
Mapcurly-braced{:name "Ada" :age 36}
HashMap(hashmap/new ...)(hashmap/new :a 1 :b 2)
Prompt(prompt ...)LLM prompt (see Prompts)
Message(message ...)LLM message (see Prompts)
Conversation(conversation/new)LLM conversation (see Conversations)
Tool(deftool ...)LLM tool definition (see Tools & Agents)
Agent(defagent ...)LLM agent (see Tools & Agents)
Promise(delay expr)Lazy evaluation
Recorddefine-record-type(define-record-type point ...)
Bytevector#u8(...) literal#u8(1 2 3), #u8()
Async Promise(async expr) or (async/resolved val)An async task result (pending, resolved, or rejected)
Channel(channel/new) or (channel/new capacity)Bounded FIFO channel for inter-task communication

Scalars

Integer

Whole numbers. Standard arithmetic applies.

sema
42
-7
0

Float

Floating-point numbers with a decimal point.

sema
3.14
-0.5
0.001

String

Double-quoted text with escape sequences.

sema
"hello"
"line\nbreak"
"\x1B;"

F-String (Interpolated String)

String interpolation with embedded expressions. f"..." reads as a (str ...) call (i.e. f"Hello ${name}" is the same as (str "Hello " name)).

sema
(define name "Alice")
f"Hello ${name}"                ; => "Hello Alice"
f"2 + 2 = ${(+ 2 2)}"           ; => "2 + 2 = 4"
f"${(:name user)} is ${(:age user)} years old"

Use \$ to include a literal dollar sign: f"costs \$5".

Boolean

#t for true, #f for false.

sema
#t
#f

Nil

The empty/null value.

sema
nil

Symbol

Bare identifiers used as variable names and in quoted data.

sema
foo
my-var
+

Keyword

Colon-prefixed identifiers. Keywords are self-evaluating and can be used as accessor functions on maps.

sema
:name
:type
:ok

;; Keywords as functions
(:name {:name "Ada" :age 36})  ; => "Ada"

Character

Character literals with #\ prefix. Named characters are supported.

sema
#\a
#\space
#\newline
#\tab

Collections

List

Parenthesized sequences. Lists are the fundamental data structure in Sema. Access the first element with car (or first) and the rest with cdr (or rest).

Why car/cdr?

These names come from the IBM 704 (1955), the machine Lisp was born on. The 704 stored each cons cell in a single 36-bit word: car ("Contents of the Address Register") extracted one 15-bit pointer field, cdr ("Contents of the Decrement Register") extracted the other. They were single hardware instructions. Sema also provides first/rest as aliases.

sema
(1 2 3)
(+ a b)
'(hello world)

Vector

Bracketed sequences with O(1) indexed access.

sema
[1 2 3]
["a" "b"]

Map

Curly-braced key-value pairs with deterministic (sorted) ordering. Maps support destructuring in let, define, lambda, and match patterns.

sema
{:name "Ada" :age 36}
{:a 1 :b 2 :c 3}

HashMap

Hash-based maps for O(1) lookup performance with many keys.

sema
(hashmap/new :a 1 :b 2 :c 3)

Bytevector

Byte arrays with #u8(...) literal syntax.

sema
#u8(1 2 3)
#u8()
(bytevector 1 2 3)
(bytevector/new 4)

Special Types

Promise

Lazy evaluation via delay/force. The expression is not evaluated until forced, and the result is memoized.

sema
(define p (delay (+ 1 2)))
(force p)       ; => 3
(promise? p)    ; => #t

Record

User-defined record types with constructors, predicates, and field accessors.

sema
(define-record-type point
  (make-point x y)
  point?
  (x point-x)
  (y point-y))

(define p (make-point 3 4))
(point-x p)    ; => 3

String Escape Sequences

EscapeDescriptionExample
\nNewline"line\nbreak"
\tTab"col1\tcol2"
\rCarriage return"text\r"
\\Backslash"path\\file"
\"Double quote"say \"hi\""
\0Null character"\0"
\x<hex>;Unicode scalar (R7RS, 1+ hex digits)"\x1B;", "\x3BB;"
\uNNNNUnicode code point (4 hex digits)"\u03BB" (λ)
\UNNNNNNNNUnicode code point (8 hex digits)"\U0001F600" (😀)
\$Literal dollar sign (in f-strings)f"costs \$5"

Type Predicates

sema
(null? '())        (nil? nil)         (empty? "")
(list? '(1))       (vector? [1])      (map? {:a 1})
(pair? '(1 2))     ; #t (non-empty list, Scheme compat)
(number? 42)       (integer? 42)      (float? 3.14)
(string? "hi")     (symbol? 'x)       (keyword? :k)
(char? #\a)        (record? r)        (bytevector? #u8())
(promise? (delay 1))  (promise-forced? p)
(bool? #t)         (fn? car)
(zero? 0)          (even? 4)          (odd? 3)
(positive? 1)      (negative? -1)
(eq? 'a 'a)        (= 1 1)

;; Scheme aliases: boolean? = bool?, procedure? = fn?
;; eq? and equal? are the same function in Sema — both do structural
;; equality without numeric coercion. Use = for numeric comparison
;; (e.g. (= 1 1.0) is #t, but (eq? 1 1.0) is #f).

;; LLM type predicates
(prompt? p)        (message? m)       (conversation? c)
(tool? t)          (agent? a)

Type Conversions

sema
(str 42)                    ; => "42" (any value to string)
(string/to-number "42")       ; => 42
(number/to-string 42)         ; => "42"
(string/to-symbol "foo")      ; => foo
(symbol/to-string 'foo)       ; => "foo"
(string/to-keyword "name")    ; => :name
(keyword/to-string :name)     ; => "name"
(char/to-integer #\A)         ; => 65
(integer/to-char 65)          ; => #\A
(char/to-string #\a)          ; => "a"
(string/to-char "a")          ; => #\a
(string/to-list "abc")        ; => (#\a #\b #\c)
(list->string '(#\h #\i))   ; => "hi"
(vector->list [1 2 3])      ; => (1 2 3)
(list->vector '(1 2 3))     ; => [1 2 3]
(bytevector/to-list #u8(65))   ; => (65)
(list/to-bytevector '(1 2 3))  ; => #u8(1 2 3)
(utf8/to-string #u8(104 105))  ; => "hi"
(string/to-utf8 "hi")          ; => #u8(104 105)
(type 42)                    ; => :int