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) # 10nums.append(5) # new IList; nums is still length 4Heads and lookups return an Option, so an empty list doesn’t
throw:
nums.head() # Some(1)IList([]).head() # Nothingnums.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.
Working with Eithers
Section titled “Working with Eithers”When you have an IList of Either, split or collect them
without a manual loop:
results.collect_ok() # IList of the Ok valuesresults.collect_err() # IList of the Err valuesresults.partition_either() # (IList[ok], IList[err])from pyrula import IMap
m = IMap({"a": 1, "b": 2})
m.get("a") # Some(1)m.get("z") # Nothingm.set("c", 3) # new IMap; m still has two keysm.remove("a") # new IMap without "a"m.contains("b") # Truekeys, 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.
Scala equivalent
Section titled “Scala equivalent”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.