Skip to main content

A functional, array-oriented, tacit programming esolang run via Python interpreter

Project description

WARNING: GUIDO VON ROSSUM WILL HATE YOU. DON'T USE THIS IN PRODUCTION CODE OR YOU'LL BE FIRED.

Iterlingua

An array-oriented tacit functional dialect for Python, inspired by APL/J.

Introduction

Iterlingua is a domain-specific language (DSL) that brings array-oriented and tacit (point-free) programming to Python. It provides a concise syntax for array manipulation, function composition, and higher-order functions.

  • If you don't even know what tacit means, or you haven't used an array-oriented language before, Iterlingua is not for you.

Installation

pip install iterlingua

Iterlingua is a pure Python package, with no dependencies. It's also compatible with MicroPython on CASIO calculators. If you want to use it on a CASIO calculator (fx-CG50 or fx-9860GIII), download the __init__.py file, rename it to iterlingua.py, and drag it into the calculator.

Quick Start

from iterlingua import *

# Basic usage
print(o("Hello World").o) # "Hello World" | Wrap & unwrap
print(o(27)[mul, 3].o) # 81 | Function application
print(o(27)[mul, 3][add, 1][div, 2].o) # 41 | Pipeline

# Array operations and pipelines
a = [ 1, 2, 3]
b = [10,20,30]
print(o(a)(0)[mul, 3][add, 1][div, 2]().o) # [2.0, 3.5, 5.0] | (0) means adding rank -> automatic broadcast
element_wise = o(a)(0)[add, o(b)(0)].o # Same rank -> Apply function element-wise
print(element_wise)  # [11, 22, 33]
cartesian = o(a)(1)[add, o(b)(0)]()().o # Different rank -> Cartesian product
print(cartesian)  # [[11,12,13],[21,22,23],[31,32,33]]

# Function composition
flatten = fixedpoint(ravel) # Flatten nested arrays
average = train(reduce(add),div,len) # Calculate average
l = [[3,1],[4,[1,5]],[[9,2],6]]
flat = flatten(l); print(flat)  # [3, 1, 4, 1, 5, 9, 2, 6]
avg = average(flat); print(avg) # 3.875

Core Concepts

1. The Rank System

The Rank System is the core mechanism of this language, deeply inspired by APL (but in APL "rank" means "depth" instead, which is different from our definition), designed to control how functions iterate over nested lists (arrays) without writing explicit loops. It separates the shape of the data from the logic of the function.

Here is a breakdown of how it works:

The Core Idea: Depth and Iteration

In Python, a 2D list like [[1, 2], [3, 4]] has a depth of 2. If you want to add a scalar 10 to every inner number, you have to write nested loops. The Rank system allows you to tell a function: "Treat this data as a collection of sub-arrays at a specific depth, and apply the function to each sub-array independently."

  • If you've known any array-oriented languages before -- Iterlingua is different! It doesn't broadcast automatically.

The _it Wrapper and Rank Tracking

Under the hood, array data is, internally, wrapped in a special _it object. An _it object stores two things:

  • l: The actual data (e.g., [[1, 2], [3, 4]])
  • r: A list of integers representing the Rank (e.g., [0, 1]) The rank list r specifies at when the function should stop descending and apply itself.

How Applying with Rank Works

When you execute a function via obj[func, other_data](will explain later), it calls the internal _f function. _f looks at the rank lists of all arguments and orchestrates the iterations. Here's how it works:

Imagine this process as a package sorting system. Inside _f there is the sorter, and the ranks are the input belts. Each round, _f looks at the current lowest rank, and accepts all elements with that rank. The rank information is preserved.

Once the sorter establishes this unified traversal route, another inner function takes over to execute the actual data extraction. It navigates through the nested lists strictly following the predefined route. At each dimension step:

  • Arguments that are marked as "active" for the current dimension advance one level deeper into their nested lists.
  • Arguments that are inactive at this dimension remain untouched, effectively broadcasting their current value to every element extracted from the active arguments.
  • The recursion continues until all predefined dimensions are exhausted. At the very bottom level, the target function f is finally applied to the collected scalar values.

Finally, the collected results are assembled back into a new nested list, tagged with the newly sorted dimension sequence, and wrapped as a fresh _it object.

Example A: Element-Wise Operation (Matching Ranks)

a = o([1, 2, 3])(0)   # _it([1,2,3], [0])
b = o([10,20,30])(0)  # _it([10,20,30], [0])
a[add, b]
  • Both have rank [0].
  • _f sees rank 0: it iterates through the outer list, pulling out scalars.
  • Executes add(1, 10), add(2, 20), add(3, 30).
  • Result: [11, 22, 33] with rank [0]. Example B: Broadcasting / Cartesian Product (Mismatched Ranks)
a = o([[1, 2], [3, 4]])(0, 1) # 2D array, ranks 0 and 1
b = o([10, 20])(1)            # 1D array, rank 1
a[add, b]
  • _f processes ranks from shallowest to deepest.
  • Rank 1: Iterates over the outer layer. a yields [1,2] and [3,4]; b yields 10 and 20.
  • Rank 0: Iterates over the inner layer for each pair.
  • Executes add(1, 10), add(2, 10), then add(3, 20), add(4, 20).
  • Result: [[11, 12], [23, 24]] with rank [0, 1].

Padding with placeholders (The Size Mismatch Rule)

If arrays at a given rank have different lengths, the system uses the first argument's size as the master size. If a shorter array runs out of elements, a special _it placeholder object is inserted. When the function is finally called with a placeholder, the system immediately returns the other argument's element unchanged (as dictated by the rule: _it in b -> return b[0]). This intentionally creates jagged padding behavior rather than implicit zip-truncation or erroring.

2. The o Wrapper

The o wrapper is the primary interface for creating rank-aware data objects. It wraps Python data (lists, scalars, etc.) into an Iterlingua object that tracks rank information.

Basic Wrapping

# Wrap a list, in this case you don't need the square brackets.
o([1, 2, 3]) # o(1, 2, 3) does the same.

# Wrap a scalar
o(42)

# Wrap nested lists
o([[1, 2], [3, 4]])

Setting Rank with ()

The () operator sets the rank for the wrapped data:

o([1, 2, 3])(0)        # Rank [0]
o([1, 2, 3])(1)        # Rank [1]
o([[1, 2], [3, 4]])(0, 1)  # Ranks [0, 1] - iterate at both levels

Multiple () calls add ranks to the list:

o([1, 2, 3])(0)(1)     # Ranks [0, 1]

Unwrapping with ()

Calling () without arguments unwraps the result, removing one level of rank tracking:

result = o([1, 2, 3])(0)[add, 10]()  # Unwraps to [11, 12, 13]

The .o Attribute

Access the underlying data with .o:

wrapped = o([1, 2, 3])
data = wrapped.o       # [1, 2, 3]

Chaining Operations

The power of o comes from chaining operations:

o(1, 2, 3)(0)[mul, 3][add, 1][div, 2]()
# Step 1: [1, 2, 3] * 3 = [3, 6, 9]
# Step 2: [3, 6, 9] + 1 = [4, 7, 10]
# Step 3: [4, 7, 10] / 2 = [2, 3.5, 5]

This is where the rank system comes into play:

o(1, 2, 3)(0)[add, o([10, 20, 30])(0)]()  # [11, 22, 33]
o(1, 2)(0)[add, o([10, 20])(1)]()()       # [[11, 21], [12, 22]]
o([1,2],[3,4])(0,1)[add, 1]()()           # [[2, 3], [4, 5]]

3. The c Composition Operator

The c operator enables tacit (point-free) programming by composing functions without explicitly naming arguments.

Basic Composition

Think c as a o-wrapped object and perform operations on it. Use a .f to retrieve the underlying function.

# Create a function that adds 1
add_one = c[add, 1].f
add_one(5)              # 6

# Create a function that multiplies by 2
double = c[mul, 2].f
double(5)              # 10

# Chaining
process = c[add, 1][mul, 2][sub, 3].f
process(5)             # ((5 + 1) * 2) - 3 = 9

4. The arg Argument Reference System

For more complex tacit expressions, Iterlingua provides argument reference objects that let you refer to arguments positionally.

Available References

Object Meaning Index
ai First argument 0 (left)
wi Second argument 1 (leftmost right)
recur Self-reference (recursion) -1 (function)
arg(n)
nth argument n

Accessing Argument Properties

# ai refers to the first argument
square = c[mul, ai].f
square(5)              # 25

# wi refers to the second argument
multiply_by_second = c[mul, wi].f
multiply_by_second(5, 3)   # 15

Transforming Arguments

You can treat arguments, again, as o-wrapped objects.

# Double the second argument, then add the first
complex_op = c[add, wi[mul, 2]].f
complex_op(5, 3)            # 5 + (3 * 2) = 11

Recursion with recur

The recur reference allows recursive definitions:

# Factorial using recursion
factorial = c[sub,1][cond,c[gt, 1],recur,const(1)][mul,ai].f
factorial(5)  # 120
# Note: this is way more efficient
factorial_iterative = c[lrange](0)[add,1]()[reduce(mul)].f

Referring to the nth argument

ai is actually an alias for arg(0), and wi is an alias for arg(1). To refer to the nth argument, use arg(n).

mapnum = c[sub,arg(1)][div,arg(1)[sub,arg(2)]][mul,arg(3)[sub,arg(4)]][add,arg(3)].f
celsius = 26
fahrenheit = mapnum(celsius, 0, 100, 32, 212) # 78.8

5. Function Trains, and other higher-order functions

A train is a way to compose functions in a fork-like pattern, inspired by APL/J language. Iterlingua also provides several higher-order functions that work seamlessly with the rank system.

  • These functions automatically adds .f to compositions, so you don't need to explicitly call .f.

The train Function

# train(left, middle, right) creates: middle(left(x), right(x))
average = train(reduce(add), div, len)
average([1, 2, 3, 4, 5])  # sum / len = 3.0

reduce - Left Fold

# Reduce with a binary function
reduce(add)([1, 2, 3, 4])      # 10
reduce(mul)([1, 2, 3, 4])      # 24

# With initial value
reduce(add, 10)([1, 2, 3])     # 16

# also see inline reduce
ireduce([1, 2, 3, 4], add, 0)  # 10

prefix - Cumulative Scan

# Running totals
prefix(add)([1, 2, 3, 4])    # [1, 3, 6, 10]
prefix(mul)([1, 2, 3, 4])    # [1, 2, 6, 24]

# Initial value like reduce
prefix(add, 10)([1, 2, 3])   # [11, 13, 16]

filter - Predicate Filtering

# Keep elements matching a condition
filter(c[gt, 3])([1, 5, 2, 8, 3])  # [5, 8]
filter(c[lt, 5])([1, 5, 2, 8, 3])  # [1, 2, 3]

fixedpoint - Iterate Until Stable

# Keep applying until result doesn't change
flatten = fixedpoint(ravel)
flatten([[1, [2, 3]], [[4]]])  # [1, 2, 3, 4]

until - Iterate Until Condition

# Double until greater than 10
until(1, c[mul, 2], c[gt, 10])  # 16

repeat - Apply N Times

# Apply negation 3 times
repeat(neg)(5, 3)  # -5 (odd number of negations)
repeat(neg)(5, 4)  # 5 (even number of negations)

6. Other useful functions

HOF Helpers

const - Constant Function

# Create a constant function that returns 10 (K combinator)
const(10)(5)  # 10

tack() - Identity Function

# Create a function that returns the first argument (I combinator generator)
tack()(5)  # 5
# Also can return the second argument
tack(1)("1st","2nd")  # "2nd"

cond - Conditional Application

# cond(value, condition, if_true, if_false)
collatz_step = c[cond,c[mod,2][eq,0],c[div,2],c[mul,3][add,1]].f

splt - Apply Multiple Functions

# Apply different functions to each element
splt([1, 2, 3], neg, c[mul, 2], c[add, 10])  # [-1, 4, 13]

slide - Sliding Window Operation

# Apply a function to each sliding window of size 2
slide([1, 2, 3, 4, 5], 2, add)  # [3, 5, 7, 9]

Debugging

Common problems

1. Compositions returning objects instead of values (Missing .f or _o)

When passing a composition (c[...]) or wrapped object (o[...]) into some functions, if the receiving function doesn't unpack it, it won't do what you expect correctly, or even worse, it will throw a TypeError. Use @adaptIterlingua to automatically unpack the arguments.

# BAD: splt doesn't automatically unpack c[...], so it returns a wrong result
def my_func(f, x):
    return f(x)
my_func(c[mul, 2], [1, 2]) # -> <_c object>
# SOLUTION: extract the function with .f first
my_func(c[mul, 2].f, [1, 2]) # -> [2, 4]
# GOOD: use adaptIterlingua decorator
@adaptIterlingua
def my_func(f, x):
    return f(x)
my_func(c[mul, 2], [1, 2]) # -> [2, 4]

Note: Iterlingua builtin functions like filter, reduce, and train automatically handle _c objects.

2. Silent padding with rank mismatches

If you combine arrays of different lengths, the system does not throw an error or truncate. It pads the shorter array with placeholders, which cause the function to simply return the other argument's element unchanged.

o([1, 2, 3])(0)[add, o([10])(0)].o 
# Expected: [11] or Error
# Actual: [11, 2, 3]  (Because add(2, placeholder) just returns 2)

Always check your array lengths if your results seem to be missing an operation.

3. Mixing up Rank setting () and Function application []

Because Python's syntax is overloaded, it's easy to mix up when to use parentheses and when to use brackets.

  • () on an o object adds rank or unwraps: o([1,2])(0)
  • [] on an o object applies a function: o([1,2])[add, 1]
  • Calling o([1,2])(add, 1) will try to set the ranks to [add, 1], which will cause it to crash.

4. Forgetting to unwrap the final result

Chaining operations keeps data wrapped in the o or _c objects. If you try to pass the result to standard Python functions (like print or len), it will fail or print the wrapper object.

  • Use .o to get the raw Python list/value from an o chain.
  • Use .f to get the callable Python function from a c chain.

iprint - Print and Return

Iterlingua provides iprint to allow you to print debug information while preserving the original value.

iprint(1, 2, 3) # prints "123" and returns 1
  • Be careful with arrays with ranks, as they'll be broadcasted automatically.

iterlingua.debug - Debugging Tool

  • The following contents are not supported on CASIO calculators, and an ANSI-supporting console is required. Instead of using from iterlingua import *, do from iterlingua.debug import *. This replaces the o wrapper with an animated version that visualizes every step of the rank system in your terminal.
from iterlingua.debug import *
o([1, 2, 3])(0)[add, 10]()

Each step is rendered as an ASCII tree showing the internal structure, then erased before the next step appears — creating a flipbook animation of how your data flows through the pipeline.

How to Read the Visualization

The debug renderer shows your data as a tree. Each node displays:

  • d0, d1, etc. — the rank at that level. This tells you that this element is not treated as a scalar.
  • > — a horizontal list of elements.
  • v — a vertical list of elements (used when nesting forces a layout break). For example, o([1, 2, 3])(0) renders as:
d0-> 1 2 3

And o([[1, 2], [3, 4]])(0, 1) renders as:

d0-> d1 d1
     v  v
     1  3
     2  4

Controlling the Animation

# Slow down the animation (default is 0.3 seconds per step)
from time import sleep
setAnimateDelay(lambda: sleep(0.5))
# Speed up
setAnimateDelay(lambda: sleep(0.1))
# Disable animation entirely (just pretty-print the final result)
setAnimateDelay(None)

When to Use It

  • Rank confusion: If your broadcasting doesn't produce the shape you expected, watch the animation to see exactly which depth the system is iterating at and where padding kicks in.
  • Composition debugging: Step through c[...] chains to see how arguments flow through each stage.
  • Understanding the rank system: The best way to learn — just try expressions and watch what happens.

Reading the Error Messages

Iterlingua doesn't throw custom errors — it relies on Python's native exceptions. Because of the heavy operator overloading, the error messages can be misleading. Remember, look at what's on the top of the Traceback first -- That's where the error occurs. Then you should look at the bottom -- here are the types you'll see most often and what they most likely mean:

Message Meaning
TypeError: '<' not supported between instances of 'function' and 'function' You probably confused ...[x] with ...(x).
TypeError: <func> takes N positional arguments but M were given You're literally passing the wrong number of arguments to the function. Most probably in c and train.
TypeError: 'int' object is not callable This is either because you forgot to wrap your data with o, or you confused ...(x) with ...[x].
TypeError: 'type' object is not subscriptable You wrote o[...] instead of o(...). Square brackets on o mean function application via __getitem__, not construction.
TypeError: object of type <type> has no len() You added a rank to a scalar by mistake.
IndexError: list index out of range Either you're trying to access an element that doesn't exist in the array, or you fed wrong number of arguments to the tack(x) or splt function.
ZeroDivisionError: integer division or modulo by zero Either you're literally dividing by zero, or you passed an empty array to trimroll.
StopIteration You passed an empty array to a reduce(...) without a start value.

Design Philosophy

Iterlingua exists for only one reason: I wanted to write APL on that poor CASIO calculator.

Not to make Python better. I just wanted to write that way—to compress a whole data pipeline into a single line of symbols and watch it flow.

Python doesn't let you do that. So I made a dialect that does. This leads to some un-Pythonic choices. I'm not apologizing for them, but I won't pretend they're accidental either:

  1. Silent Padding In APL, when you apply a function to arrays of different ranks, it just raises an error. In Python (using zip), it just truncates the longer array. I dislike both, so I designed this silent padding feature.
  2. You Set Rank Yourself In both APL and NumPy, the broadcast mechanism is automatically inferred. As the Zen of Python wrote, "Explicit is better than implicit", I prefer to declare the rank explicitly.
  3. Operators Are Functions In both APL and Python, the operators are symbols. In APL, they are functions. In Python, they are syntax. But, APL operators do too much things, and Python's operators aren't functions (this is the limit). So, the + operator is written as add.
  4. Tacit / Point-Free by Default APL doesn't make you name arguments if you don't want to. You just compose functions and let the data flow through. Python forces you to say lambda x: x + 1. Iterlingua lets you say c[add, 1].f -- no x, no lambda, no noise. The c wrapper exists purely so you can build functions without ever mentioning their inputs.
  5. Chain or Die Everything returns a wrapper, everything chains. There's no "oh, this returns a raw list so I need to wrap it again." o([1,2,3])(0)[add, 1][mul, 2]().o is one breath. The .o at the end is actually not required if you're not chaining, but if you forget it when returning to Python, you deserve what you get.

If these choices make you uncomfortable, Iterlingua is probably not for you. That's fine -- Python is already an excellent language.

Performance

Iterlingua is actually slow, despite the fact that I've tried my best to optimize it.

Every [func, arg] operation traverses nested lists recursively. There is no lazy evaluation, no C extensions, no JIT. On a CASIO calculator, this doesn't matter. On a server processing million-element arrays, it matters a lot.

What you're doing What you should use
< 1,000 elements, nested lists, exploring ideas Iterlingua is fine
Heavy numeric computation, large matrices NumPy or JAX
Production data pipelines Pandas or Polars
CASIO calculator / no install rights Iterlingua is just the right tool

Why not make it faster?

Two reasons:

  1. I wanted to write APL, not a compiler. Making Iterlingua fast would require either a complete rewrite in C (now it's NumPy) or a JIT compiler (now it's JAX). At that point it's not a hack anymore -- it's a job.
  2. The CASIO constraint. If I can't fit the source in my head and the runtime in 60KB of RAM, I've lost the plot.

If you're measuring performance, you're already using the wrong tool.

API Reference

Operators' Aliases

Operator Name Operator Name
x+y add x-y sub
x*y mul x/y div
x//y floordiv x%y mod
-x neg x<y lt
x>y gt x<=y le
x>=y ge x==y eq
x!=y ne x or y lor
x and y land not x lnot
x|y bor x&y band
x^y bxor x<<y bshl
x>>y bshr x[y] get
x[y:z] slice x[:y] take
x[y:] drop x in y inside

Array Construction

Function Description Example
clist Coerce to list clist((1,2)) -> [1,2]
lrange list(range(*a)) lrange(1,5) -> [1,2,3,4]
enclose Wrap in list enclose(3) -> [3]

Array Trimming & Padding

Function Description Example
trimwhile Trim from end while condition holds trimwhile([1,2,0,0],eq(0)) -> [1,2]
trimroll Trim or roll to fill length trimroll([1,2],5) -> [1,2,1,2,1]
trimfill Trim or fill to length trimfill([1,2],4,0) -> [1,2,0,0]
padto Pad to length (doesn't trim) padto([1,2],4,0) -> [1,2,0,0]

Array Restructuring

Function Description Example
reverse Reverse reverse([1,2,3]) -> [3,2,1]
rotate Circular shift rotate([1,2,3,4],1) -> [4,1,2,3]
ravel Flatten one level ravel([[1,2],[3]]) -> [1,2,3]
zip Transpose (no truncation) zip([[1,2],[3,4]]) -> [[1,3],[2,4]]
regroup Group by fixed size regroup([1,2,3,4],2) -> [[1,2],[3,4]]
window Sliding windows window([1,2,3,4],3) -> [[1,2,3],[2,3,4]]
splice Replace slice splice([1,2,3,4],1,3,[9]) -> [1,9,4]
amend Replace at index amend([1,2,3],1,9) -> [1,9,3]
sortk Sort by key function sortk(['bb','a'],len) -> ['a','bb']

Array Selection & Search

Function Description Example
grade Indices that would sort grade([3,1,4]) -> [1,0,2]
dgrade Duplicative ranking dgrade([3,1,4,1]) -> [2,0,3,0]
indexes Indices of matching items indexes([1,2,1],1) -> [0,2]
find Find sublist positions find([1,2,3,2,3],[2,3]) -> [1,3]
filter(f) Filter by predicate filter(c[gt,3])([1,5,2]) -> [5]
compress Keep items where mask is truthy compress([1,2,3],[1,0,1]) -> [1,3]
unique Remove duplicates (first occurrence) unique([1,2,1,3]) -> [1,2,3]

Array Partitioning & Grouping

Function Description Example
rpartition Partition by adjacent equal keys rpartition([1,1,2],[1,1,2]) -> [[1,1],[2]]
spartition Group by key (sorted) spartition([1,2,3],[1,2,1]) -> [[1,3],[2]]
runlen Run-length encoding runlen([1,1,2,2,2]) -> [2,3]
runsqz Squeeze adjacent duplicates runsqz([1,1,2,2,1]) -> [1,2,1]

Functional Programming

Function Description Example
apply Apply function to unpacked tuple apply((3,5),add) -> 8
cond Conditional apply cond(5,c[gt,3],neg) -> -5
commute(f,idx) Swap arg 0 and arg idx commute(sub)(5,3) -> -2
revf(f) Apply f to reversed, then reverse revf(window)([1,2,3],2) -> [[3,2],[2,1]]
splt Apply each function to each element splt([1,2],neg,enclose) -> [-1,[2]]

Higher-Order Functions & Helpers

Function Description Example
reduce(f,[start]) Left fold reduce(add)([1,2,3]) -> 6
prefix(f,[start]) Cumulative scan prefix(add)([1,2,3]) -> [1,3,6]
ireduce Reduce with initial value (swapped) ireduce([1,2,3],add,0) -> 6
repeat(f)(x,n,...) Apply f n times repeat(neg)(5,2) -> 5
until(v,f,t) Apply f until t(v) is true until(1,c[mul,2],c[gt,10]) -> 16
fixedpoint(f,limit) Iterate until stable fixedpoint(sorted)([3,1,2]) -> [1,2,3]
slide Apply f to sliding windows slide([1,2,3],2,add) -> [3,5]
train(lf,mf,*rf) Fork train train(sum,div,len)([1,2,3]) -> 2
const(x) Return constant function const(5)(9) -> 5
tack(n) Return nth argument function tack(1)(7,8) -> 8

License

Iterlingua is licensed under the Unlicense.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

iterlingua-0.1.0.tar.gz (28.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

iterlingua-0.1.0-py3-none-any.whl (18.3 kB view details)

Uploaded Python 3

File details

Details for the file iterlingua-0.1.0.tar.gz.

File metadata

  • Download URL: iterlingua-0.1.0.tar.gz
  • Upload date:
  • Size: 28.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.4

File hashes

Hashes for iterlingua-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a96966effb894c212f2779549c8c45945abbc7608e9b4a490dddbf997a9e4d9a
MD5 4c9476a32095f47962d0a22eb83f2bed
BLAKE2b-256 599345fa6e669e60d1b79320f6e42038025d3f57136dbb20e25a3e857a49b16d

See more details on using hashes here.

File details

Details for the file iterlingua-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: iterlingua-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.4

File hashes

Hashes for iterlingua-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c24b9815513a6b03f9e5b214e8c77f658ad19bb4244d8a98ff9fac0ae02c32a0
MD5 ed0ad942739747cb0c30697a74b75bc3
BLAKE2b-256 28ad3d89ca771dc06f41ba3b01939e5a153148be54a4ca14b8d1503295116323

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page