Read a little. Try a little.

Ideas you
can run.

Start with a complete program and its result. The examples below have been checked against native alpha.13. The bundled examples match your native toolchain.

Model a rule

guarded types

Name a domain constraint and let the compiler check its use.

Read the example →
Calculate exactly

fractions and decimals

Preserve exact values and make representability explicit.

Read the example →
Handle success and failure

Option and Result

Use tagged values and exhaustive matching instead of hidden failure conventions.

Run the example →
Transform data

collections and bytes

Work with persistent arrays, maps, sets and byte values.

Run the example →
Explore algorithms

Fibonacci and Project Euler

Study memoization, iteration, arithmetic and conditional branches.

Run Fibonacci →
Describe related values

records

Give a task named fields and turn its state into a readable message.

Run the example →
Work with text

sorting filenames

Sort names with a pure comparison function, then select a suffix.

Run the example →
Local packages

Share a function

Create a library and an application in two neighbouring folders.

Build the example →
Native HTTP tool

Serve files over HTTP

Serve files from any chosen directory with the installed Panackelty HTTP server.

Serve files over HTTP →

New in alpha.12

Organise programs
across files.

These complete, multi-file programs run from the alpha.13 release tree. Each can be checked and run from source, then compiled and run as saved bytecode.

New in alpha.12

Choose the first
matching branch.

Ordered conditional chains

Each condition is checked in order. Only the first matching body runs.


pure classify(value: Nat): Str {
  if value == 0 {
    "zero"
  } else if value == 1 {
    "one"
  } else if value == 2 {
    "two"
  } else {
    "many"
  }
}

main(): Void {
  print(classify(0))
  print(classify(2))
  print(classify(7))
}

Output


zero
two
many
Alpha.11 example

Give a business rule a name

Positive expresses a constraint on an integer. Code receiving this type can state its expectation directly.


type Positive = Int where value > 0

pure triple(n: Positive): Int {
  n * 3
}

main(): Void {
  answer: Positive = 14
  print(triple(answer))
}

Output


42
Works with alpha.13

Exact fractions, explicit conversions

exact.panackalpha.13

main(): Void {
  third = 1/3
  print((third * 30).nat())
  print((1/8).dec())
}
$ panack run exact.panack

10
0.125

Exact fractions, exact conversions. An unrepresentable exact conversion fails instead of silently rounding.

Build on the basics

Values, data
and decisions.

Works with alpha.13

Handle a failure explicitly

A Result carries either a value or an error. Exhaustive matching makes both paths visible.


pure safe_divide(numerator: Nat, denominator: Nat): Result[Nat,Str] {
  if denominator == 0 {
    Error("division by zero")
  } else {
    Ok(quotient(numerator, denominator))
  }
}

pure describe(result: Result[Nat,Str]): Str {
  match result {
    Ok(value) => "value ${value}",
    Error(message) => message
  }
}

main(): Void {
  print(describe(safe_divide(84, 2)))
  print(describe(safe_divide(1, 0)))
}

Output


value 42
division by zero
Works with alpha.13

Keep the original collection

Appending returns a new array. Updating a persistent map also returns a new value; assign it when you want to keep the change.


main(): Void {
  original: [Nat] = [1, 2]
  extended: [Nat] = original.append(3)

  print(original)
  print(extended)

  mut scores: Map[Str,Nat] = map()
  scores = scores.put("Ada", 42)
  print(scores.get("Ada"))
}

Output


[1, 2]
[1, 2, 3]
42
Works with alpha.13

Describe a task with a record

Give related values named fields, then keep presentation in a pure function.


record Task {
  title: Str,
  done: Bool
}

pure describe_task(task: Task): Str {
  title = task.title

  if task.done {
    "Done: ${title}"
  } else {
    "To do: ${title}"
  }
}

main(): Void {
  task = Task("Try Panackelty", false)
  print(describe_task(task))
}

Output


To do: Try Panackelty
Works with alpha.13

Sort and select filenames

Pass a named pure comparison function to sort_by, then use a string predicate to select matching names. This processes names; it does not read the filesystem.


import stdlib/prelude

pure name_before(left: Str, right: Str): Bool {
  left < right
}

main(): Void {
  files = ["z.txt", "b.panack", "a.panack"].sort_by(@name_before)

  for file in files {
    if file.ends_with(".panack") {
      print(file)
    }
  }
}

Output


a.panack
b.panack
Works with alpha.13

Build a result one step at a time

Local mutation can be useful inside a pure calculation. Each iteration advances the two values in the sequence.


pure fibonacci(n: Nat): Nat {
  mut previous: Nat = 0
  mut current: Nat = 1

  for ignored in 0..n {
    next: Nat = previous + current
    previous = current
    current = next
  }

  previous
}

main(): Void {
  print(fibonacci(10))
}

Output


55

What did the compiler check?

See why a subtraction is safe or why a pure function cannot print. Explore panack explain →

For larger programs, explore the release-specific example folder, including Project Euler, enums, higher-order functions and native networking.

Native alpha.13 · local packages

Share a function
between packages.

Create a small greeting library and an application that uses it. You write four files in two neighbouring folders. After installing native alpha.13, everything in this example is local.

1. Create the folders

In a terminal, choose a directory for the example and run:

mkdir -p package-demo/greetings/src package-demo/hello/src
cd package-demo

The completed layout will be:

package-demo/
  greetings/
    panack.json
    src/greeting.panack
  hello/
    panack.json
    src/main.panack

2. Write the library

Create greetings/src/greeting.panack. This pure function returns a greeting; pub makes it available to callers outside its module.

pub pure hello(name: Str): Str {
  "Hello, ${name}!"
}

Create greetings/panack.json to declare the library and its public module:

{
  "schema": 1,
  "package": "example.greetings",
  "version": "0.1.0",
  "language": "modules-v1",
  "toolchain": "0.1.0-alpha.13",
  "source": "src",
  "exports": {
    "greeting": "greeting.panack"
  },
  "dependencies": {}
}

source names the source folder. The greeting export exposes src/greeting.panack under that logical module name. A library has no entry point. Both manifests pin alpha.13 because package toolchains must match exactly.

3. Write the application

Create hello/panack.json. Its dependency alias greetings points to the library next door:

{
  "schema": 1,
  "package": "example.hello",
  "version": "0.1.0",
  "language": "modules-v1",
  "toolchain": "0.1.0-alpha.13",
  "source": "src",
  "entry": "main.panack",
  "exports": {},
  "dependencies": {
    "greetings": {
      "path": "../greetings"
    }
  }
}

../greetings is resolved from the application manifest’s folder, not your terminal’s working directory. The application entry is src/main.panack. Its exports are empty because it does not publish library modules.

Create hello/src/main.panack:

import greetings/greeting as greeting

main(): Void {
  print(greeting.hello("Ada"))
}

In greetings/greeting, the first name is the dependency alias and the second is the library’s exported module. as greeting gives that module a short name inside this file. The application calls the library’s pure function and prints its result.

4. Run it

From package-demo, run:

panack check --project hello/panack.json
panack run --project hello/panack.json

The check prints ok. The application prints:

Hello, Ada!

Change "Ada" in the application and run it again. Or change the greeting in the library: the application uses the updated function on its next source run.

You can move the whole package-demo folder and keep using the same commands and relative dependency. Moving just one package would break that relative path. This example needs no registry, package download or Git checkout.

Native alpha.13

Serve files
over HTTP.

The native installation includes panack-http-server, a general-purpose static HTTP server for any chosen directory. It can serve documents, generated reports, website assets and other files. This example uses a small HTML page; no source checkout is needed:

mkdir preview-demo
printf '%s\n' '<h1>Hello from Panackelty</h1>' > preview-demo/index.html
panack-http-server --root ./preview-demo --port 4173 --no-cache --noindex

Wait for Serving http://127.0.0.1:4173/, then open that address in your browser. Edit index.html and refresh to see your change. Press Ctrl-C to stop; active requests have up to one second to drain.

--root chooses the served folder. --no-cache asks the browser not to store responses, and --noindex asks search engines not to index them. The default bind address is loopback, so other devices cannot connect. Use another free port if 4173 is already occupied.

The tool serves existing files and directory indexes with confined reads. It does not list directories, rebuild generated sites, watch files or provide TLS. Complete responses must fit within its 1 MiB limit.

All command options and shutdown behaviour →

Keep exploring

Explore Panackelty.