curry.expressions module

Building Curry expressions from Python.

expr is the typed builder: it types the expression over the schemes of the front end, converts Python values by the expected type, and supplies the class dictionaries (see curry.typecheck.builder). raw_expr is the untyped builder, which converts by the Python type alone and checks only the arity; it serves the runtime and the tests of the runtime. The markers of this module (anchor, choice, cons, fail, free, nil, ref, typed, unboxed) describe the parts of an expression that are no Python value.

class curry.expressions.anchor(value, name=None)[source]

Bases: object

Used with expr() to create an anchor in an expression. This can be used to construct nonlinear expressions.

When no argument is supplied, the anchor name is automatically generated from the sequence _1, _2, …, according to its position in a left-to-right, depth-first traversal.

class curry.expressions.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.

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

Bases: object

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

curry.expressions.describe(interp, *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.expressions.expr(interp, *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.expressions.fail = <curry.expressions._failcls object>

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

class curry.expressions.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.

class curry.expressions.fwd(value)[source]

Bases: object

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

curry.expressions.nil = <curry.expressions._nilcls object>

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

curry.expressions.raw_expr(interp, *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.expressions.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.expressions.result_type(interp, node)[source]

The defaulted type expr() recorded for a node, or None.

class curry.expressions.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.expressions.typeof(e, 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.expressions.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.

curry.expressions.untyped_expr(interp, *args, **kwds)[source]

The untyped builder with the markers of expr(): a free marker is its shared unknown node and a choice marker a call of Prelude.?. This is expr() with the flag typed_expr off. The interpreter uses it for the expressions it builds around compiled code, whose types the front end checked.