curry package

The Sprite Curry system.

This package contains everything one needs to compile and execute Curry code. The topmost module provides an instance of the Curry system and an API to interact with it.

To perform a soft reset call reset(). This returns the system to its original state, with no definitions and no modules imported. The configuration is taken from environment variable SPRITE_INTERPRETER_FLAGS. To change that at runtime, call reload() and specify new flags.

Use import_() to import Curry modules, compile() to compile Curry code, expr() to build Curry expressions, and eval() to evaluate them. path determines where Sprite searches for Curry code. Loaded modules can be found under modules. Use topython() to convert Curry values to Python objects. stats() reports the statistics of the run: time, rewrite steps, forks, collections, memory, compile time, and collector time.

Example

>>> mymodule = curry.compile("""
... data Item = A | B
... rotate A = B
... rotate B = A
... main :: Item
... main = rotate A ? rotate B
... """)
>>> for value in curry.eval(mymodule.main):
...   print(value)
B
A
class curry.choice(cid, lhs, rhs=None)[source]

Bases: object

Used with expr() to place a choice into a Curry expression.

Through expr, the choice is a call of Prelude.?, whose rewrite step draws a fresh id from the interpreter; cid is not used. Through raw_expr, it is a Choice node with the id cid, 0 by default.

curry.compile(mode='module', imports=None, exprtype=None, modulename=None)[source]

Compile a string containing Curry code. In mode ‘module’, the string is interpreted as a Curry module. In mode ‘expr’, the string is interpreted as a Curry expression.

Parameters:
  • string – A string containing Curry code.

  • mode – Indicates how to interpret the string (see above).

  • imports – A list specifying additional modules to import. The elements can be strings or CurryModule objects. Import statements will be prepended to the code string and CURRYPATH will be adjusted accordingly. This can be useful when importing dynamically-compiled modules whose names and locations are difficult to obtain.

  • exprtype – A string specifying the expression type. This is what would appear to the right of :: in a Curry type annotation for the expression. Used only in ‘expr’ mode. Without it, the class constraints of the expression are defaulted with the table of the PAKCS REPL: Num to Int, Fractional to Float, Monad to IO, a lone Data to Bool; see curry.typecheck.defaulting.

  • modulename – Specifies the module name. Used only in ‘module’ mode. The module is placed in curry.interpreter:Interpreter.modules under that name. By default, a unique name is chosen, which no later compile reuses.

Returns:

In ‘module’ mode, a CurryModule. In ‘expr’ mode, a Curry expression. A text that ends in where x, y free declares free variables, as in the REPL. A variable whose type is absent from the result type of the expression cannot show in a value, so curry.eval yields each value of such an expression with its binding (Bindings); a variable whose type occurs in the result type is left in the value. The REPL of PAKCS prints the binding of every declared variable. With exprtype, or with a comment after free, the clause stays a local declaration and no binding is reported.

Raises:

CompileError – The front end rejects the text, or, in ‘expr’ mode without exprtype, the table cannot default a class constraint.

class curry.cons(head, tail0, *tail)[source]

Bases: object

Used with expr() to place one or more list constructors into a Curry expression.

curry.currytype(ty)[source]

Gets the Curry type corresponding to a Python type. For instance, for the Python bool type, this returns the type object for Prelude.Bool.

curry.describe(*args, **kwds)[source]

The description of an expression: the arguments of expr() as a tree, typed only when a consumer asks for its node. The DSL builds descriptions at every operator and types them once at the boundary, so that an outer context fixes the types of the inner parts. A description is an argument of expr() and of eval; str prints it in Curry syntax; its method typeof gives its type. The keyword exprtype states the type of the description; the other keywords are its anchors. See Description.

curry.eval(*args, **kwds)[source]

Evaluate a Curry goal.

Parameters:
  • *args – Positional arguments that specify the goal. These are passed to Interpreter.expr. One function symbol whose scheme has class constraints and no value parameter, a goal without a signature such as main = Just 5, is applied to its dictionaries first: the constraints are defaulted with the table of the PAKCS REPL (see curry.typecheck.defaulting), so the goal evaluates to a value and not to a partial application. An expression of curry.compile(mode='expr') whose text declared where x free variables absent from its result type yields its values with the bindings of those variables (curry.typecheck.goals.Bindings).

  • converter – Keyword-only argument specifying the converter to use when returning results. The default is ‘default’, the flag defaultconverter. 'topython' applies curry.topython(), None and any other name leave the Curry value, and a callable f(interp, value) converts as it pleases. See :func:curry.interpreter.conversions.getconverter.

  • exprtype – Keyword-only argument: the type of the goal in Curry syntax, passed to Interpreter.expr.

  • **kwds – Any other keyword names an anchor, as in Interpreter.expr.

Raises:
Returns:

A generator producing the values of the specified Curry program.

curry.expr(*args, **kwds)[source]

Builds a Curry expression.

The expression is typed before it is built (see curry.typecheck.builder): the type schemes of the symbols are read from the FlatCurry interfaces of their modules, the arguments are unified with the parameter types, the class constraints are defaulted with the table of the PAKCS REPL, and the class dictionaries are supplied. So expr(curry.symbol('Prelude.+'), 1, 2) builds the call of the method at Int, and expr(P.show, [P.Just, 1]) finds the Show instance of Maybe Int. A typing failure raises CurryTypeError at construction; nothing is evaluated. The flag typed_expr turns the typing off.

The arguments specify the expression to build. Each positional argument must be directly convertible to Curry or describe a node. A Python value converts by the type its position expects:

  • bool: Converted to Prelude.Bool.

  • int Prelude.Int; Prelude.Float under Float; the fromInt conversion under another Num instance.

  • float Converted to Prelude.Float.

  • str Under [Char] one string of any length. Elsewhere a string of length one is a Prelude.Char, and another string is [Char].

  • list Converted to a Curry list, in a loop. Every element takes the element type, so [1, 2.5] is [Float].

  • tuple Converted to a Curry tuple.

  • iterator Lazily converted to a Curry list. The element type is fixed when the expression is built; an item that does not convert ends the evaluation with an EvaluationError.

  • None An error that names the expected type.

  • a Curry node Typed by a walk of its content, up to 100000 nodes; curry.typed(node, 'T') states the type instead. A node alone passes through untouched.

Any (possibly nested) sequence whose first element is an instance of NodeInfo specifies a node. The remaining arguments are recursively converted to Curry expressions to form the successors list. Thus, given suitable definitions, it is possible to build the Curry list [0,1,2] with the following code:

expr([Cons, 0, [Cons, 1, [Cons, 2, Nil]]])

Fewer arguments than the symbol takes give a partial application; more arguments go through Prelude.apply when the result is a function. A symbol without a type scheme (a module without a FlatCurry interface, or a built-in of Sprite’s own Prelude) is built untyped when it stands alone, as the goal of a saved module does, and is an error when it is applied to arguments; typeof() refuses it either way.

Several special symbols are provided. See anchor, choice, cons, fail, free, nil, ref, typed, and unboxed. A free marker becomes a call of Prelude.unknown, one node per marker, and a choice marker a call of Prelude.?, so the runtime assigns the ids. raw_expr builds the raw Free and Choice nodes instead. An unboxed marker stands only as the payload of a primitive, [Prelude.Int, curry.unboxed(3)]; anywhere else it is a CurryTypeError.

Parameters:
  • interp – An interpreter object.

  • *args – Positional arguments used to construct expressions.

  • **kwds – Keyword arguments specifying subexpressions that may be referenced via ref. Each keyword specifies the name of an anchor. See the examples below.

  • exprtype – Keyword-only argument. The type of the expression in Curry syntax, for example 'Maybe Float'. Its type variables are rigid.

  • target – Reserved keyword-only argument. If a target is supplied, then it will be rewritten with the specified expression. Otherwise a new node is created.

Returns:

A Curry expression. Its type is recorded, so typeof() answers for it, and eval converts its values by it.

curry.fail

Places a failure into a Curry expression.

curry.flags

The flags attribute of the global interpreter. Change its entries in place to reconfigure the interpreter, curry.flags['defaultconverter'] = 'topython'. An assignment to curry.flags rebinds the name in the package and changes nothing in the interpreter.

class curry.free(vid=0, exprtype=None)[source]

Bases: object

Used with expr() to place a free variable into a Curry expression.

Through expr, one marker is one variable. The builder makes one node for the marker, a call of Prelude.unknown applied to the Data dictionary of its type, and reuses it for every occurrence of the marker, in that expression and in later ones. The first rewrite step on the node creates the variable with a fresh id and forwards the node to it. The node belongs to one interpreter state: curry.reset installs a new state, and the marker becomes a new variable there. exprtype fixes the type of the variable, in Curry syntax; without it the type comes from the context, and a variable whose type stays polymorphic gets the dictionary of Bool, which unknown never reads. Through raw_expr, every occurrence is a separate Free node with the id vid, 0 by default; that form serves the tests of the runtime.

curry.getInterpreter()[source]

Get the global interpreter instance.

curry.import_(currypath=None, is_sourcefile=False)[source]

Import one or more Curry modules.

Parameters:
  • arg – A module descriptor indicating what to import. A module descriptor is a module name (string), curry.icurry.IModule object, or a sequence of module descriptors.

  • currypath – The search path for Curry files. By default, self.path is used.

  • is_sourcefile – Indicates whether to interpret arg as a source file name rather than a module name.

Returns:

A CurryModule or sequence thereof.

curry.load(filename, **kwds)[source]

Loads a Curry module saved with save().

Aside from how the file is located, this follows the import protocol, so the module is added to the interpreter’s modules dict.

Parameters:
  • filename – The path to a file to load. The file type and suffix must match the interpreter.

  • from_plan – True when the import plan loads the current object of a module it imports, False for a file the user named (the C++ backend decides some refusals by it; see its loader).

Returns:

A CurryModule.

curry.module(name)

Look up a module by name.

curry.modules

The modules attribute of the global interpreter. This is a dict that contains the imported Curry modules.

curry.nil

Places a list terminator into a Curry expression.

curry.path

The path attribute of the global interpreter. Initialized from environment variable CURRYPATH. Change it in place to adjust the Curry search path, curry.path.insert(0, '.'). An assignment to curry.path rebinds the name in the package and changes nothing in the interpreter.

curry.raw_expr(*args, **kwds)[source]

The untyped builder. Equivalent to expr() without the types: every Python value converts by its Python type, only the arity of a symbol is checked, no dictionary is supplied, a free marker becomes a raw Free node with the id of the marker, a new node per occurrence, and a choice marker a raw Choice node with the id of the marker. Fewer arguments than the arity of a symbol give a partial application; a function applied to more goes through Prelude.apply, one node per surplus argument, as a point-free definition needs; a constructor applied to more is an error. An expression that is not well typed evaluates with undefined behaviour.

class curry.ref(name=None)[source]

Bases: object

Used with expr() to create a reference to a named subexpression. This can be used to construct nonlinear expressions.

The argument is optional when the expression contains exactly one anchor at the point where the reference appears.

curry.reload(flags={})[source]

Hard-resets the interpreter. Any flags supplied will be forwarded to the constructor, overriding flags supplied via the environment variable SPRITE_INTERPRETER_FLAGS.

curry.reset()

Soft-resets the interpreter.

Clears the loaded modules, except the Prelude and the packages. Restores I/O streams to their defaults, resets the Curry path from the environment, releases the expression modules, and clears the signature table. The names of anonymous modules are not reused; see compile.py. This is much faster than building a new interpreter, which loads the Prelude.

curry.save(filename=None, goal=None, **kwds)[source]

Saves a Curry module.

Parameters:
  • cymodule – The argument to dump. Must be a valid argument to inspect.geticurry.

  • filename – A file name, stream, or None. If None, a string is returned. Otherwise, the file is created, if specified, and the output is written to the file or stream.

  • goal – The goal the saved program evaluates when it runs, unless -g on its command line names another. A program needs one: without goal the call raises ValueError (issue #35). To save a module without a main program, for load(), pass module_main=False. A goal with class constraints and no signature is defaulted with the table of the PAKCS REPL at run time; the file records its type, so it runs from any directory. A goal the table cannot default raises here, at save time. On the C++ backend the saved file is C++ source, and its record names the source of the module relative to the directory of the object (the product directory beside the source, .curry/<subdir>/). Compile the file in that directory, as sprite-make --so does; an object compiled elsewhere loads, but its module has no source file (backends.cxx.loader.source_file).

  • kwds – Additional keyword arguments passed to IBackend.write_module. Possibly specific to the backend.

Returns:

If filename is None, the module contents are returned as a string. Otherwise, None.

curry.show_value(value)[source]

Converts a Python Curry value to a string in Curry format. This does a few things, such as lowering one-tuples; adjusting containers, such as tuples and lists, to print elements as with str rather than repr; and converting free variable to friendly names _a, _b, etc. The output should match other Curry systems.

curry.stats()[source]

Reports the statistics of the run.

Returns:

wall

Seconds since this process started (on Linux; elsewhere, since the Curry system was imported). The start time of a process has a resolution of one clock tick, 10 ms on most systems.

cpu

User plus system CPU seconds of this process. Child processes, such as the Curry front end and the C++ compiler, are not included.

steps

The rewrite steps taken by the evaluations of this interpreter, a running evaluation included. A soft reset keeps the count.

forks

The number of times a configuration forked at a choice in those evaluations.

collections

The collections run in this process by the node collector of the C++ backend. The Python backend reports zero.

peak_rss

The peak resident set size of this process, in bytes.

compile

Seconds this process spent in the steps of the toolchain: the Curry front end, the ICurry-JSON conversion, the code generator, and the C++ compiler. Zero when every file was current.

gc_seconds

Seconds the node collector of the C++ backend spent in its collections. The Python backend reports zero.

swapped

The functions that tiered execution of the C++ backend swapped from the interpreter to compiled code in this process (the interpreter flag interpret set to ‘tiered’). The Python backend reports zero.

failed_compiles

The background compiles of tiered execution that failed in this process; the modules stay interpreted. The Python backend reports zero.

gc_roots_seconds, gc_trace_seconds, gc_sweep_seconds, gc_registries_seconds

Seconds the collections of the node collector spent in each phase: the roots (the configurations of the queues and the nodes Python holds), the trace from the roots, the block sweep, and the registries (the free-variable tables, the generator nodes, the queues and the sets). The verifier of the stress mode is in none of them. The Python backend reports zero.

gc_marked, gc_marked_old, gc_marked_young

The nodes the collections marked: all, those marked in the collection before as well (old), and those allocated since (young).

gc_configurations_pushed

The configurations whose roots the collections pushed.

gc_queues_destroyed, gc_configurations_destroyed

The queues of set functions no root reached, destroyed by the collections, and the configurations destroyed with them.

gc_old_redexes, gc_old_slot_writes, gc_old_nodes_written, gc_old_blocks

The writes into old nodes between the collections: the writes of a step into an old redex, the other pointer writes into an old node, the distinct old nodes written, and the blocks with such a write, summed over the intervals. Only a runtime built with the write counters (make GC_WRITE_COUNTERS=1) counts them; the default build reports zero.

A C++ runtime built with the scheduler counters (make COUNTERS=1) adds the keys of SCHEDULER_KEYS; see scheduler_fields().

Return type:

A Stats object, a dict with these keys, in this order

curry.symbol(modulename=None)

Look up a symbol by its fully-qualified name, 'Prelude.+'. The name splits at its first dot into a module and a name in it, so 'Data.List.nub' needs the package Data loaded, as an import of Data.List leaves it. The second parameter has no effect.

curry.topython(convert_strings=True, exprtype=None)[source]

Converts a Curry value to Python by substituting built-in types.

This functions converts (recursively) the types int, float, str, bool, list, and tuple. Other types are passed through untouched.

Parameters:
  • value – The Curry value to convert.

  • convert_strings – If True, then lists of characters are converted to Python strings.

  • exprtype – The static type of the value, in Curry syntax or as a FlatCurry type, or None. The type is threaded through the lists and the tuples: an empty list under [Char] converts to '', while a list under a type variable or without a type converts to a string when it holds characters. curry.eval passes the type of the goal it built.

Raises:

NotConstructorError – Non-ground data was encountered along a list spine.

Returns:

The value converted to Python.

curry.type(name)

Returns the constructor info tables for the named type.

class curry.typed(value, exprtype)[source]

Bases: object

Used with expr() to annotate a part of an expression with its type: curry.typed(value, 'T') converts value at the type T, in Curry syntax, and unifies T with the type the context expects. So curry.typed('a', 'String') is the string "a", and curry.typed(node, '[Int]') states the type of a large value instead of a walk of its content. raw_expr builds the value and ignores the annotation.

curry.typeof(defaulted=False)[source]

The type of an expression in Curry syntax. Without defaulted the undefaulted scheme, what :type prints: typeof(expr(plus, 1, 2)) is Num a => a. With defaulted the type after the table of the PAKCS REPL: Int. e is a node expr() returned, any other Curry node (typed by its content), a symbol, a description of describe(), or any argument expr() accepts.

class curry.unboxed(value)[source]

Bases: object

Used with expr() to place the unboxed payload of a primitive into a Curry expression: [Prelude.Int, curry.unboxed(3)] is the node <Int 3>, and Prelude.Char and Prelude.Float take the marker the same way. A plain Python value builds the same node, so the marker is seldom needed. The payload must fit the primitive: a Python int under Int, a str of length one under Char, a float under Float; another value is a CurryTypeError from both builders (unboxed_payload()). Anywhere else the marker is a CurryTypeError at construction, from both builders: alone, in a list or a tuple, or as the argument of another symbol, a node is expected, and an unboxed value in its place is an ill-formed node, which ended the process on the C++ backend (issue #107). An item of an iterator is converted when the list is demanded, so the marker there is an EvaluationError at that time.

Subpackages

Submodules