@Dennis Why does dyadic_chain have a call to create_chain while monadic_chain does chain = chain[0].chain? It seems like in the end they accomplish similar things but I might be lost here. Let me know if this question is not clear enough.
@dylnan create_chain is only called in parse_code and some quicks, so I don't think I understand the entire question. chain = chain[0].chain is tail call optimization and only happens if not chain[1:].
Haha sorry, I'm realizing how unclear that question was now. Let me be more specific
Say we have the program + with args 1 and 2
In the first iteration of the while loop of dyadic_chain, chain[0] is a dict for a chain. i.e. hasattr(chain[0], 'chain') is true
So when we get brought to dyadic_link from this line, return link.call(larg, rarg) is evaluated, but link.call is create_chain
And this call to create_chain seems to be where the chain of the while loop in dyadic_chain changes from a chain dictionary to a list of dicts of links.