Programs and modules

A .ki file is a module. Top-level forms run when it loads, as a Python file’s do on import.

Running

Python

python prog.py
python -i prog.py
python

Koskari

koskari prog.ki
koskari -i prog.ki
koskari

Where do .ki files live?

Beside your .py files, in the same packages and on the same sys.path. Once import koskari has run, Python’s import mypkg.mod finds mypkg/mod.ki. Running a script adds its directory to the path, as Python does.

The shape of a file

Python

"""Process names from argv."""

import sys


def process(name):
    print("hello", name)


def main():
    for name in sys.argv[1:]:
        process(name)


if __name__ == "__main__":
    main()

Koskari

"""
Process names from argv
"""

import sys


def process [name]:
  print "hello" name


@entry-point
def main []:
  for-each [name (item-slice sys.argv 1)]:
    (process name)

What is @entry-point?

The mark on the function that runs when the file is executed as a program and not when it is imported. Where Python guards a block with if __name__ == "__main__": and runs it while the module is still loading, Koskari calls the marked function once the module has finished loading, and its return value is the exit status: None is 0, an int is that status. main is still an ordinary function that a test or another module can call. Comments are ; to the end of the line, doubled by custom.

Comprehensions

Python

squares = [x * x for x in range(6)]

Koskari

var squares:
  list-each [x (range 6)]:
    (* x x)

Python

evens = [x for x in xs if x % 2 == 0]

Koskari

var evens:
  list-each [x xs] when: (== 0 (% x 2)):
    x

Python

lengths = {w: len(w) for w in words}

Koskari

var lengths:
  dict-each [w words] key: w value: (len w)

Python

gen = (x * x for x in xs)

Koskari

var gen:
  each [x xs]:
    (* x x)

Which one is which?

list-each builds a list, dict-each a dict, each a generator. All three take the [var seq] binding that for-each takes, and a when: or unless: clause on the header filters. A for-each loop is for side effects; the -each family is for values.

Imports

Python

import math
import os.path
from pathlib import Path
from functools import lru_cache as memoize
from mypkg import *

Koskari

import math
import os.path
import-from pathlib Path
import-from functools [lru_cache as: memoize]
import-all-from mypkg

Does import os.path bind os?

Yes, as in Python. import [os.path as: p] binds the leaf module directly.

Packages

Python

mypkg/
  __init__.py
  tools.py

Koskari

mypkg/
  __init__.py
  tools.ki

Does the __init__ have to be Python?

No; __init__.ki works, and so does no __init__ at all, which gives a namespace package as it would in Python. A Python __init__.py that runs import koskari is the common choice, since it turns the import hook on for anyone who imports the package. The rules, including the one trap, a foo.py beside a foo.ki, are in Modules and packages.

Run it

Save as squares.ki:

def squares [n]:
  list-each [i (range n)]:
    (* i i)

@entry-point
def main []:
  print (squares 6)
[0, 1, 4, 9, 16, 25]

To ship a .ki program as a pip-installed command, see Packaging an installed command.