top of page
Functions

Several marcel operators take functions as arguments. Marcel functions are written in Python. For example, the files produced by the ls operator can be piped to the select operator, which uses a function to keep only files modified in the past day:

M 0.18.3 jao@loon ~/git/marcel/marcel$ ls | select (lambda f: now() - f.mtime < days(1))
drwxrwxr-x   jao    jao        4096   2023 Oct 27 11:54:55   __pycache__
-rw-rw-r--   jao    jao       13314   2023 Oct 27 11:54:55   env.py
-rw-rw-r--   jao    jao       10895   2023 Oct 27 11:54:55   main.py
drwxr-xr-x   jao    jao        4096   2023 Oct 27 11:54:55   object
-rw-rw-r--   jao    jao       39519   2023 Oct 27 11:54:55   parser.py

Functions are always delimited by parentheses. Here, the function takes one argument, f, which will be bound to Files piped in from ls. now() is a function built in to marcel which returns the current time, as seconds since the epoch. f.mtime returns the modification time of file f. days(1) invokes another builtin function that returns the number of seconds in one day.

The net effect is to filter the Files returned by ls by keeping only those modified in the last day. Remember that an out operator is appended if needed, so this command prints the qualifying files.

 

Marcel allows lambda to be omitted, so the function could have been written as (f: now() - f.mtime < days(1)).

The map operator uses a function to transform incoming data. For example, this command lists the name and size of each .py file in the current directory:

M 0.18.3 jao@loon ~/git/marcel/marcel$ ls *.py | map (f: (f.name, f.size))
('__init__.py', 652)
('api.py', 8299)
('argsparser.py', 19326)
('builtin.py', 1817)
('core.py', 19539)
('env.py', 13314)
('exception.py', 4523)
('function.py', 3158)
('helpformatter.py', 20752)
('job.py', 11452)
('jsonutil.py', 1081)
('locations.py', 1736)
('main.py', 10895)
('multilinereader.py', 6700)
('nestednamespace.py', 2558)
('opmodule.py', 3465)
('parser.py', 39519)
('picklefile.py', 3683)
('reduction.py', 1522)
('reservoir.py', 1207)
('tabcompleter.py', 8101)
('util.py', 6006)
('version.py', 672)

You can write functions with no arguments. For example, to evaluate 2**50:

M 0.18.3 jao@loon ~/git/marcel/marcel$ map (2 ** 50)
1125899906842624

Marcel allows map to be omitted. A function invocation by itself is understood to be part of a map operator. So this works too:

M 0.18.3 jao@loon ~/git/marcel/marcel$ (2 ** 50)
1125899906842624

In Python, the symbols in a function are resolved against a namespace. Marcel functions run in the marcel namespace, a Python namespace maintained by marcel. This namespace includes environment variables, so you can use this abbreviated notation to examine environment variables:

M 0.18.3 jao@loon ~/git/marcel/marcel$ (USER)
jao

You can add symbols to the marcel namespace in a number of ways:

  • import modules in ~/.marcel.py, the configuration file.

  • Define symbols in ~/.marcel.py.

  • Import them.


For example, math.pi is not present in the marcel namespace by default:

M 0.18.3 jao@loon ~/git/marcel/marcel$ (pi)
Error: Running map(lambda: pi): name 'pi' is not defined
M 0.18.3 jao@loon ~/git/marcel/marcel$ (math.pi)
Error: Running map(lambda: math.pi): name 'math' is not defined

However, you can import math, and then use its symbols:

M 0.18.3 jao@loon ~/git/marcel/marcel$ import math
M 0.18.3 jao@loon ~/git/marcel/marcel$ (math.pi)
3.141592653589793

import math * would import the symbols contained in math, similar to the Python statement from math import *.

bottom of page