Skip to the content.

Modules

Fun’s module system allows you to organize code across multiple files and share functionality between programs.

Table of Contents

Module Basics

Every .fun file is a module. A module can contain:

Creating Modules

Simple Module

# math.fun
inc = \x -> x + 1
dec = \x -> x - 1
double = \x -> x * 2

# Export all functions as a record
{
    inc: inc,
    dec: dec,
    double: double
}

Module with Type Annotations

# types.fun
# Define types for better documentation
inc : Lam<Int, Int>
inc = \x -> x + 1

dec : Lam<Int, Int>
dec = \x -> x - 1

# Export with type information
{
    inc: inc,
    dec: dec
}

Module with Imports

# advanced.fun
import basic from `./basic`

# Use imported functions
factorial = fix(\rec -> \n ->
    when n == 0 is
        True -> 1;
        False -> n * rec(basic.dec(n))
)

# Export new functions
{
    factorial: factorial,
    # Re-export imported functions
    inc: basic.inc,
    dec: basic.dec
}

Importing Modules

Basic Import

# main.fun
import math from `./math`

# Use imported functions
result = math.inc(5)    # result: 6
sum = math.inc(10) + math.dec(5)  # result: 14

Import with Alias

# main.fun
import utils from `./math`

# Use with different name
result = utils.inc(5)   # same as math.inc(5)

Multiple Imports

# main.fun
import math from `./math`
import types from `./types`

# Use functions from different modules
result1 = math.inc(5)
result2 = types.dec(10)

Nested Imports

# main.fun
import advanced from `./advanced`

# Use functions that were re-exported
result = advanced.factorial(5)  # uses advanced.factorial
inc_result = advanced.inc(3)    # uses math.inc via re-export

Exporting Values

Record Exports

The most common way to export values is using a record:

# utils.fun
inc = \x -> x + 1
dec = \x -> x - 1
square = \x -> x * x

# Export as record
{
    inc: inc,
    dec: dec,
    square: square
}

Single Value Export

You can export a single value directly:

# constants.fun
PI = 3.14159
E = 2.71828

# Export single value
PI

Function Export

# factorial.fun
factorial : Lam<Int, Int>
factorial = fix(\rec -> \n ->
    when n == 0 is
        True -> 1;
        False -> n * rec(n - 1)
)

# Export function directly
factorial

Selective Export

# library.fun
# Internal helper functions (not exported)
internal_helper = \x -> x * 2

# Public API functions
public_inc = \x -> x + 1
public_dec = \x -> x - 1

# Export only public functions
{
    inc: public_inc,
    dec: public_dec
}

Module Paths

Relative Paths

# Import from same directory
import math from `./math`

# Import from parent directory
import shared from `../shared`

# Import from subdirectory
import utils from `./utils/helpers`

# Import from sibling directory
import common from `../common/lib`

File Extensions

# .fun extension is optional
import math from `./math`        # looks for math.fun
import math from `./math.fun`    # explicit extension

# Any file extension is supported
import data from `./data.txt`    # non-standard extension
import config from `./config`    # no extension

Directory Traversal

# Multiple levels up
import root from `../../root`

# Deep nesting
import deep from `./nested/very/deep/module`

# Absolute paths (relative to project root)
import global from `/src/global`

Module Structure

Complete Module Example

# user.fun

# 1. Imports
import math from `./math`
import types from `./types`

# 2. Type annotations
User : {name: Str, age: Int}
create_user : Lam<Str, Int, User>
get_name : Lam<User, Str>

# 3. Function definitions
create_user = \name, age -> {name: name, age: age}

get_name = \user -> user.name

is_adult = \user -> user.age >= 18

# 4. Internal helper functions
validate_age = \age -> age >= 0

# 5. Export record
{
    create_user: create_user,
    get_name: get_name,
    is_adult: is_adult,
    # Re-export useful functions from other modules
    inc: math.inc,
    dec: math.dec
}

Module Organization

# Recommended module structure:

# 1. Module documentation
# user.fun - User management functions

# 2. Imports
import math from `./math`

# 3. Type definitions
User : {name: Str, age: Int}

# 4. Constants
MIN_AGE = 0
MAX_AGE = 150

# 5. Public functions
create_user = \name, age -> {name: name, age: age}

# 6. Private helper functions
validate_age = \age -> age >= MIN_AGE && age <= MAX_AGE

# 7. Export record
{
    create_user: create_user,
    MIN_AGE: MIN_AGE,
    MAX_AGE: MAX_AGE
}

Best Practices

Module Naming

# Use descriptive names
math.fun              # Mathematical functions
user_management.fun   # User-related functions
string_utils.fun      # String utilities

# Avoid generic names
utils.fun             # Too generic
lib.fun               # Too generic

Export Strategy

# Export only what's needed
# Good: Selective export
{
    public_function: public_function,
    public_constant: public_constant
}

# Avoid: Export everything
{
    public_function: public_function,
    internal_helper: internal_helper,  # Should be private
    debug_function: debug_function     # Should be private
}

Import Organization

# Group imports logically
# Standard library imports
import math from `./math`
import string from `./string`

# Third-party imports
import external from `./external/lib`

# Local imports
import user from `./user`
import auth from `./auth`

Module Dependencies

# Avoid circular dependencies
# Good: Hierarchical structure
math.fun              # No dependencies
user.fun              # Depends on math.fun
app.fun               # Depends on user.fun

# Bad: Circular dependency
# user.fun imports from app.fun
# app.fun imports from user.fun

Type Safety

# Use type annotations for public APIs
public_function : Lam<Int, Str>
public_function = \x -> `{x}`

# Internal functions can rely on type inference
internal_helper = \x -> x * 2

Documentation

# Document your modules
# user.fun
# User management module
# Provides functions for creating and manipulating user records

import math from `./math`

# Create a new user with name and age
create_user : Lam<Str, Int, {name: Str, age: Int}>
create_user = \name, age -> {name: name, age: age}

# Check if user is an adult
is_adult : Lam<{name: Str, age: Int}, Bool>
is_adult = \user -> user.age >= 18

{
    create_user: create_user,
    is_adult: is_adult
}

Common Patterns

Utility Module

# utils.fun
# Common utility functions

# String utilities
to_upper = \str -> `{str}`  # Placeholder for actual implementation
to_lower = \str -> `{str}`  # Placeholder for actual implementation

# List utilities
head = \list ->
    when list is
        Cons x xs -> x;
        Nil -> error "empty list"

tail = \list ->
    when list is
        Cons x xs -> xs;
        Nil -> error "empty list"

{
    to_upper: to_upper,
    to_lower: to_lower,
    head: head,
    tail: tail
}

Configuration Module

# config.fun
# Application configuration

# Database settings
DB_HOST = "localhost"
DB_PORT = 5432
DB_NAME = "myapp"

# Application settings
APP_NAME = "Fun App"
APP_VERSION = "1.0.0"
DEBUG_MODE = True

{
    DB_HOST: DB_HOST,
    DB_PORT: DB_PORT,
    DB_NAME: DB_NAME,
    APP_NAME: APP_NAME,
    APP_VERSION: APP_VERSION,
    DEBUG_MODE: DEBUG_MODE
}

Type Module

# types.fun
# Common type definitions

# User types
User : {name: Str, age: Int}
Admin : {name: Str, age: Int, permissions: List<Str>}

# Result types
Result : {success: Bool, data: a, error: Str}

# Export type constructors (if supported)
{
    User: User,
    Admin: Admin,
    Result: Result
}

The module system provides a clean way to organize code and share functionality across your Fun programs. Use it to create reusable libraries and maintainable codebases.