Skip to content
Pyrula

IList and IMap

IList and IMap are immutable. Every operation returns a new collection and leaves the original alone. They’re structurally shared under the hood, so the copies are cheap rather than full clones.

from pyrula import IList
nums = IList([1, 2, 3, 4])
nums.map(lambda n: n * 2) # IList([2, 4, 6, 8])
nums.filter(lambda n: n % 2 == 0) # IList([2, 4])
nums.fold_left(0, lambda acc, n: acc + n) # 10
nums.append(5) # new IList; nums is still length 4

Heads and lookups return an Option, so an empty list doesn’t throw:

nums.head() # Some(1)
IList([]).head() # Nothing
nums.find(lambda n: n > 2) # Some(3)

Other operations: tail, last, take, drop, distinct, prepend, concat, flat_map, to_list, length, is_empty. IList is iterable, so for x in nums and comprehensions work.

When you have an IList of Either, split or collect them without a manual loop:

results.collect_ok() # IList of the Ok values
results.collect_err() # IList of the Err values
results.partition_either() # (IList[ok], IList[err])
from pyrula import IMap
m = IMap({"a": 1, "b": 2})
m.get("a") # Some(1)
m.get("z") # Nothing
m.set("c", 3) # new IMap; m still has two keys
m.remove("a") # new IMap without "a"
m.contains("b") # True

keys, values, and items return an IList. map_values and filter_values transform the values, merge combines two maps, and to_dict gives you a plain dict back.

Because nothing mutates in place, you can hand these to other code without defensive copies, and they’re safe to share across threads.

IList is Scala’s immutable List/Vector and IMap is its immutable Map, both persistent and structurally shared. The methods match: map, filter, fold_left (foldLeft), and head/find returning an Option instead of throwing.