from __future__ import print_function
import json
struct = json.loads(open('staff.json','r').read())
staff = struct['staff']
salaries = struct['salaries']
def visit_pets(staff, cond, visit):
for person in staff:
for pet in person["pets"]:
if (cond((person, pet))):
visit((person, pet))
# Find all cats owned by any of our employees
visit_pets(staff, lambda t: t[1]["type"] == "cat", lambda t: print(t[1]))
# Find each pet and their owner
visit_pets(staff, lambda t: True, lambda t: print("{} belongs to {}".format(t[1]["name"], t[0]["name"])))
# Give a $5 raise to anyone who owns a dog
dog_owners = set()
visit_pets(staff, lambda t: t[1]["type"] == "dog", lambda t: dog_owners.add(t[0]["id"]))
for staff_id,salary in salaries.items():
if staff_id in dog_owners:
salaries[staff_id] += 5
In my view it gets you 80% of the power of optics in exchange for zero machinery and can be understood by almost anyone. For doing these kinds of ops on a deeper structure, using Scala/Javascript or something with first-class support for HOFs, folds/filters/maps would work better.I wish more people promoted this view of FP - just pure functions, higher order functions and referential transparency. It gives you the ability to reason locally and extend code well. The remaining type system and architecture astronomy buys very little in relation to what it costs.