Skip to content

Structured values and ownership

hmath_value.h represents exact scalars, lists, tuples and original Haskell objects used by the structured C APIs. Each domain header declares named operations with the original argument order. The mathematical implementation remains in Haskell.

Lifetime

Every successful output owns one reference. Release it with hmath_value_release; retain an additional reference with hmath_value_retain. Releasing a null pointer is allowed. Inputs are borrowed for the duration of a synchronous call. A returned object or container holds its Haskell values independently of the input handles, so input handles can then be released.

Each live handle keeps the runtime active. Release all handles before the final hmath_shutdown. Immutable values may be shared between concurrent calls when each caller keeps a reference alive. Output locations must be independent; releasing the final reference concurrently with a call using that handle is invalid. Context cancellation and limits follow the individual domain contract.

Python domain objects provide close() and context managers. Ordinary scalar, list and tuple results are converted to Python values. Objects returned inside containers retain independent native references.

Value kinds

hmath_value_info(value, &kind, &dtype, &count) queries metadata without changing the last-error state. All three output pointers are required. A dtype of -1 means the object has no scalar coefficient type. count is logical length; interpretation for an opaque object is specified by its domain.

Kind Representation
0 Nothing, represented by Python None
1 Typed scalar coefficient
2 Haskell Int, represented with ptrdiff_t
3 Boolean
4 List
5 Tuple, including ()
6–8 Polynomial, power series, rational function
9 Dense matrix
10 Haskell String
Other Opaque object declared by its domain header

Maybe a uses kind 0 for Nothing and the value's own representation for Just. Tuple/list shape remains significant: an empty list, unit tuple and Nothing are distinct values. Consult the specific function's contract where an interface uses unit only to signal success.

Construct scalars

Every constructor takes hmath_context *context first and hmath_value **out last. A null context selects the default execution context. On failure, the output pointer is unchanged.

Constructor Input and coefficient type
hmath_value_f32 float, binary32
hmath_value_f64 double, binary64
hmath_value_complex_f32 Real and imaginary float, Complex Float
hmath_value_complex_f64 Real and imaginary double, Complex Double
hmath_value_integer Signed decimal ASCII, arbitrary-precision Integer
hmath_value_integral Integral dtype plus signed decimal ASCII; rejects values outside that type
hmath_value_rational Decimal numerator and nonzero denominator; exact normalized Rational
hmath_value_index ptrdiff_t, Haskell Int
hmath_value_boolean C integer, zero false and nonzero true
hmath_value_none No payload, Nothing

Coefficient enums distinguish binary32/binary64, complex64/complex128, arbitrary Integer, exact Rational, signed and unsigned 8/16/32/64-bit integers and native-width Int/Word. A domain operation determines which original Haskell instances it supports. It rejects mismatched types rather than silently choosing a different mathematical domain.

Binary constructors preserve the selected floating representation, including signed zero and NaN/Inf. The called mathematical function applies its original finite-input policy. Exact constructors never convert through floating point.

Construct and inspect containers

hmath_value_list and hmath_value_tuple take an array of borrowed const hmath_value * items and a size_t count. The resulting container owns the contained Haskell values independently of those item handles. A null array is permitted only when count is zero.

hmath_value_item(context, sequence, index, out) accepts a list or tuple and returns an independently owned item. Indices are zero-based Haskell Int values; out-of-range indices fail.

#include <hmath_value.h>

/* After hmath_init has succeeded: build an exact pair (1/3, 2/7). */
hmath_value *a = NULL, *b = NULL, *pair = NULL;
hmath_status status = hmath_value_rational(NULL, "1", "3", &a);
if (status == HMATH_OK)
    status = hmath_value_rational(NULL, "2", "7", &b);
if (status == HMATH_OK) {
    const hmath_value *items[] = {a, b};
    status = hmath_value_tuple(NULL, items, 2, &pair);
}
hmath_value_release(a);
hmath_value_release(b);
/* pair remains valid here if status == HMATH_OK. */
hmath_value_release(pair);

Read scalars and strings

All getters borrow their input. Required output addresses must be nonnull. They reject an incompatible kind or dtype and preserve outputs on failure.

Getter Result
hmath_value_get_f32 Real and imaginary float; accepts binary32 or complex64
hmath_value_get_f64 Real and imaginary double; accepts binary64 or complex128
hmath_value_get_exact Two owned decimal strings, numerator and denominator; integers use denominator 1
hmath_value_get_index ptrdiff_t from kind 2
hmath_value_get_boolean C integer Boolean from kind 3
hmath_value_get_text Unicode codepoints from kind 10 into a caller-owned buffer

Both floating outputs are required; real inputs produce imaginary zero. Free each string from hmath_value_get_exact with hmath_value_string_free, which also accepts null. These strings use their own allocation and remain valid after the input handle is released.

hmath_value_text takes uint32_t Unicode codepoints and their explicit count. This preserves every Haskell Char, including embedded NUL and surrogate codepoints, without normalization. For hmath_value_get_text, obtain the count with hmath_value_info, then provide that many elements. An undersized buffer fails without changing its contents. String length counts codepoints, not UTF-8 bytes.

Errors

Each operation returns hmath_status. Representation errors, allocation failure, cancellation and runtime lifecycle errors use the C ABI status codes. A checked Haskell Left MathError returns HMATH_MATH_ERROR (11), with its original constructor and payload available through hmath_last_math_error in hmath_error.h. Read the payload before another operation changes the thread's last error.

Python raises HMathError; its math_error field contains the structured Haskell error when status is 11. Unexpected Python exceptions in callbacks are retained and re-raised after native cleanup. Domain documentation specifies whether a callback may return a recoverable mathematical error and whether an operation can retain that callback.