Python Lambda Late Binding Bug Charged 500 Wrong
- A lambda is syntactic sugar for a single-expression anonymous function — Python compiles it to the exact same bytecode as an equivalent def, so there is no performance difference between them. Anyone who tells you otherwise has not checked the bytecode.
- Lambdas belong inline at call sites for
sorted(),map(), andfilter()where the logic is a single readable expression used exactly once. The moment you assign a lambda to a variable, name it, or need more than one expression, def is the correct choice without exception. - Assigning a lambda to a variable is an explicit PEP 8 anti-pattern — if it has a name, it deserves def, because def gives you a real name in tracebacks, docstring support, type hint support, and per-function error grouping in monitoring tools.
- A lambda is an anonymous, single-expression function — syntactic sugar that compiles to the same bytecode as an equivalent def
- Best used inline with sorted(), map(), and filter() where you pass a quick throwaway function as an argument at the call site
- Cannot contain statements — no assignments, loops, try/except blocks, or multi-line logic allowed
- Performance is identical to def — choose based on readability and reusability, never on speed
- Assigning a lambda to a variable is an anti-pattern per PEP 8 — use def instead so tracebacks carry a real function name
- The loop-variable late binding trap is the most common lambda bug in production — fix it with lambda i=i: ... to capture by value at definition time
- map() and filter() return lazy iterators in Python 3 — wrap in list() when you need to materialize the result or iterate more than once
Lambda Quick Debug Cheat Sheet
Lambda traceback with no function name — '<lambda>' is all you have
grep -n 'lambda' your_file.pypython3 -c "import dis; f = lambda x: x*2; dis.dis(f)"All loop-created lambdas return the same value — late binding trap confirmed
python3 -c "fns = [lambda: i for i in range(5)]; print([f() for f in fns])"python3 -c "fns = [lambda i=i: i for i in range(5)]; print([f() for f in fns])"SyntaxError on a lambda line blocking deployment
python3 -m py_compile your_file.pyflake8 --select=E999,W605 your_file.pyProduction Incident
Production Debug GuideSymptom → Action quick reference for lambda-related runtime issues — ordered by frequency of occurrence
print() calls, if/elif/else blocks, or multi-line logic. Lambdas only support single expressions. Refactor the logic into a named def function with an explicit return statement. Run python -m py_compile your_file.py to verify the fix before deploying.filter() appears to return an empty result or produces no output→In Python 3, both map() and filter() return lazy iterators, not lists. The iterator is exhausted after the first pass. Wrap in list() to materialize the full result: list(map(lambda x: x*2, data)). If you need to iterate the result more than once, store the materialized list in a variable rather than calling map() or filter() again.Every Python codebase eventually hits a moment where you need to pass a small piece of logic — a sort key, a quick transformation, a one-line filter — to a function that expects another function as its argument. You could define a full function with def, give it a name, and move on. But when that logic is just one expression and you will only use it once, that ceremony feels like wearing a tuxedo to check the mailbox. Lambda functions exist to fill exactly that gap, and they appear constantly in professional Python code.
The problem lambdas solve is verbosity at the call site. When you are sorting a list of dictionaries by a nested key, or filtering a dataset by a quick boolean condition, stopping to write a five-line named function breaks your flow and populates your module namespace with a function that will never be called again. Lambdas let you express that logic inline, right where it belongs, keeping your code readable and your namespace uncluttered.
But the line between appropriate and abusive lambda usage is narrower than most developers realize, especially early in their Python career. I have reviewed codebases where lambdas were assigned to variables, nested inside other lambdas, and used for multi-step logic that had no business being in a single expression. Those codebases are genuinely painful to debug — particularly when a production traceback shows '<lambda>' with no useful name and you are scrolling through a 400-line module at 3 AM trying to figure out which of twelve anonymous functions is responsible for the billing error.
By the end of this guide you will understand not just the syntax but the actual reasoning behind when to reach for a lambda versus a named function. You will see them working correctly inside sorted(), map(), and filter() — the three places they genuinely shine in production code — and you will know the specific gotchas that catch experienced developers off guard, particularly the late binding closure trap that silently produces wrong results with no error message.
What a Lambda Actually Is — And What It Deliberately Is Not
A lambda in Python is an anonymous function — a function defined without a name, expressed in a single line. The keyword lambda is followed by zero or more parameters, a colon, and a single expression whose value is implicitly returned. That is the entire contract: one expression, implicit return, no name required.
Here is the mental model that matters: a lambda is not a special kind of function with unique powers. Under the hood, Python compiles a lambda to the exact same bytecode as an equivalent def function. There is no runtime distinction whatsoever. Lambdas do not run faster. They do not use less memory. They are not more Pythonic by virtue of being shorter. They exist for one reason only: to reduce ceremony when a full def definition would be overkill for the situation.
What a lambda cannot do is equally important to understand. It cannot contain statements — no assignments, no loops, no try/except blocks, no print() calls (which are function calls, not statements, but the intent to do side-effect work is a signal you need def). If your logic requires more than a single expression, the lambda is not the right tool. Trying to compress complex logic into a lambda does not demonstrate sophistication; it demonstrates a desire to be clever at the expense of the next developer who has to read and maintain your code.
The def versus lambda decision comes down to commitment. The more logic will be reused, the more it deserves a name. The more throwaway and inline a piece of logic is, the more a lambda earns its place. Learning to feel that distinction — not just know the rules — is what makes the difference between code that reads naturally and code that requires a second pass to decode.
# ── Understanding what a lambda actually is ── # A full named function — has a name, lives permanently in the module namespace, # appears by name in tracebacks, can carry a docstring and type hints def apply_discount_named(price: float) -> float: """Apply a 10% discount to the given price.""" return price * 0.9 # The exact same logic as a lambda — no name, no docstring, no type hints # Assigning it to a variable like this is actually a PEP 8 anti-pattern, # but it illustrates what a lambda IS before we get to where it BELONGS apply_discount_lambda = lambda price: price * 0.9 # Both are callable objects — Python's type system treats them identically original_price = 49.99 print(apply_discount_named(original_price)) # 44.991 print(apply_discount_lambda(original_price)) # 44.991 — same result, same computation # Python reports the same type for both — there is no 'lambda type' print(type(apply_discount_named)) # <class 'function'> print(type(apply_discount_lambda)) # <class 'function'> — identical type # The difference shows up in tracebacks and introspection print(apply_discount_named.__name__) # 'apply_discount_named' — useful in debugger print(apply_discount_lambda.__name__) # '<lambda>' — useless in a 3 AM incident print() # Lambda with multiple parameters — comma-separated, same as def calculate_line_total = lambda unit_price, quantity, tax_rate: unit_price * quantity * (1 + tax_rate) print(calculate_line_total(9.99, 3, 0.08)) # 32.3676 # Lambda with no parameters — valid but rarely needed outside tests get_placeholder = lambda: "N/A" print(get_placeholder()) # N/A # Conditional expression (ternary) inside a lambda — the right way to branch classify_score = lambda score: "pass" if score >= 50 else "fail" print(classify_score(72)) # pass print(classify_score(31)) # fail
44.991000000000004
<class 'function'>
<class 'function'>
apply_discount_named
<lambda>
32.3676
N/A
pass
fail
- A lambda compiles to the exact same bytecode as an equivalent def — there is no performance difference, ever. Anyone who tells you otherwise is wrong.
- It exists to reduce ceremony at the call site, not to add power — one expression, implicit return, no name required and no name given
- The moment you assign it to a variable, you have converted an anonymous function into a named function with none of the benefits of naming — use def so the name appears in tracebacks and the function can carry a docstring
- Think of it as a Post-it note versus a filing cabinet entry: one is for quick throwaway use that you will discard, the other is for anything that deserves a permanent record
Where Lambdas Actually Belong — sorted(), map(), and filter()
The three canonical homes for lambdas in real Python code are sorted(), map(), and filter(). Each of these functions accepts another callable as an argument, and that is the precise use case lambdas were designed for: passing a compact piece of logic to a higher-order function without stopping to name it.
sorted() with a key argument is the most common and most natural lambda usage in production code. When you have a list of complex objects — dictionaries, dataclass instances, namedtuples, or objects with multiple attributes — and you need to sort by a specific field or a derived value, a lambda expressing that key is clear, readable, and immediately understood by anyone who knows Python. It does not clutter the namespace and it cannot be accidentally called somewhere it should not be.
map() applies a transformation function to every element of an iterable and returns an iterator of results. When the transformation is a single expression — format a string, scale a value, extract a field — a lambda is precisely the right vehicle. When the transformation requires branching, error handling, or multiple steps, pull it into a named function and pass that.
filter() retains only the elements for which the function returns a truthy value. Simple predicate conditions — checking a field value, testing a range, verifying a type — are well-suited to lambda. Multi-condition predicates that require documentation to explain belong in a named function with a docstring.
A practical threshold I apply in code review: if you have to read a lambda twice to understand what it does, it should be a named function. Lambdas should be self-explanatory at a single glance. If they require mental parsing to decode, they are costing more in readability than they are saving in lines of code.
# ── Real production patterns where lambda earns its place ── # EXAMPLE 1: Sorting a list of employee records by various keys employees = [ {"name": "Priya", "department": "Engineering", "salary": 95000, "tenure_years": 4}, {"name": "Marcus", "department": "Marketing", "salary": 72000, "tenure_years": 7}, {"name": "Chen", "department": "Engineering", "salary": 110000, "tenure_years": 2}, {"name": "Fatima", "department": "HR", "salary": 68000, "tenure_years": 9}, {"name": "Jordan", "department": "Engineering", "salary": 88000, "tenure_years": 3}, ] # Single-field sort — classic lambda use case by_salary_desc = sorted(employees, key=lambda emp: emp["salary"], reverse=True) print("By salary (highest first):") for emp in by_salary_desc: print(f" {emp['name']:<10} ${emp['salary']:,}") print() # Multi-key sort using a tuple — lambda returning a tuple sorts by first element, # then by second element for ties. Clean and self-explanatory. by_dept_then_salary = sorted( employees, key=lambda emp: (emp["department"], -emp["salary"]) # dept alphabetically, salary descending ) print("By department, then salary within department:") for emp in by_dept_then_salary: print(f" {emp['department']:<15} {emp['name']:<10} ${emp['salary']:,}") print() # EXAMPLE 2: map() — apply a transformation to every element # Computing total compensation (salary + 15% bonus) for each employee total_compensation = list( map(lambda emp: {**emp, "total_comp": round(emp["salary"] * 1.15)}, employees) ) print("Total compensation (salary + 15% bonus):") for emp in total_compensation: print(f" {emp['name']:<10} ${emp['total_comp']:,}") print() # EXAMPLE 3: filter() — keep only elements matching a condition # Senior engineers: Engineering department with 3+ years tenure senior_engineers = list( filter( lambda emp: emp["department"] == "Engineering" and emp["tenure_years"] >= 3, employees ) ) print("Senior engineers (Engineering dept, 3+ years):") for emp in senior_engineers: print(f" {emp['name']} — {emp['tenure_years']} years") print() # EXAMPLE 4: Chaining map and filter — keep lazy for efficiency on large datasets # Filter to affordable prices, then format as currency strings raw_prices = [29.99, 49.99, 9.99, 149.99, 89.99, 19.99] tax_rate = 0.08 # Chain stays lazy until list() materializes it — efficient for large datasets formatted_affordable = list( map( lambda price: f"${price:.2f}", filter( lambda price: price <= 50.00, map(lambda p: round(p * (1 + tax_rate), 2), raw_prices) ) ) ) print("Affordable prices after tax (formatted):", formatted_affordable)
Chen $110,000
Priya $95,000
Jordan $88,000
Marcus $72,000
Fatima $68,000
By department, then salary within department:
Engineering Chen $110,000
Engineering Priya $95,000
Engineering Jordan $88,000
HR Fatima $68,000
Marketing Marcus $72,000
Total compensation (salary + 15% bonus):
Priya $109,250
Marcus $82,800
Chen $126,500
Fatima $78,200
Jordan $101,200
Senior engineers (Engineering dept, 3+ years):
Priya — 4 years
Jordan — 3 years
Affordable prices after tax (formatted): ['$32.39', '$10.79', '$21.59']
- Wrapping in
list()materializes the full result in memory immediately — fine for small datasets, potentially dangerous for millions of records where you only need the first few results - In ETL pipelines and data processing, keep iterators lazy through the full transformation chain to avoid loading everything into memory at once
- The most common beginner mistake: iterating the same
map()orfilter()result twice and getting nothing on the second pass — the iterator was already exhausted. Store the result in a list variable if you need multiple passes. - When chaining
map()andfilter()operations, the entire chain stays lazy until you consume it — this is a real memory efficiency win on large datasets
list.sort() with the same key lambda modifies the list in place and avoids the allocation.map() and filter() catches developers off guard in two specific scenarios: first, when you want to print or log the result for debugging (an iterator prints as a memory address, not its contents); second, when you write it to a variable expecting it to behave like a list. Both situations require wrapping in list().list(). If you are piping into another operation that also consumes lazily, keep the chain lazy and only materialize at the final output stage.map(), and filter() are the three canonical homes for lambda in production Python. Inline key functions and simple transformations at call sites are where lambdas genuinely improve code clarity.Lambda vs def — A Decision Framework That Removes All Ambiguity
The choice between lambda and def is not about style preferences or team conventions. It is about matching the tool to the job, and there is a clear decision framework that handles every case without ambiguity.
Four questions, asked in order. First: does the logic fit in a single expression that produces a value? If no — if you need assignments, loops, try/except blocks, or multiple statements — use def. Lambdas cannot handle statements; this is not a limitation to work around, it is a boundary that exists for a reason. Second: will this function be called more than once, or used in more than one place? If yes, use def and give it a name. Reusable logic deserves to be findable, testable, and documentable. Third: does this function need a docstring or type hints for clarity or tooling support? If yes, use def. Lambdas support neither. Fourth: is this function being passed as an argument at a call site where def would require you to write the function ten lines above and then scroll back to the call? If yes, lambda is the right choice — provided the first three questions all said no.
The other dimension to get right is the late binding closure trap, which is specific to lambdas created inside loops. When you create a lambda inside a for loop that references the loop variable, the lambda does not capture the current value of that variable — it captures a reference to the variable itself. When the loop finishes and you call the lambdas, they all evaluate the variable at call time, which means they all see the final value from the last iteration. The fix is mechanical and must become reflexive: bind the loop variable as a default argument. The pattern lambda i=i: ... looks redundant but it is doing essential work — default argument values are evaluated at function definition time, so each lambda gets its own copy of i's current value.
Produc-code wisdom: the most expensive lambda in a codebase is not the one with the most logic — it is the one that is producing silent wrong results because of late binding, and the team has been debugging the wrong layer of the stack for two hours.
# ── The decision framework in practice ── users = [ {"username": "alex_92", "age": 31, "verified": True, "score": 88, "plan": "pro"}, {"username": "beta_tester","age": 17, "verified": False, "score": 72, "plan": "free"}, {"username": "carol_dev", "age": 25, "verified": True, "score": 95, "plan": "enterprise"}, {"username": "dan_h", "age": 19, "verified": True, "score": 61, "plan": "pro"}, {"username": "eve_ml", "age": 28, "verified": True, "score": 79, "plan": "free"}, ] # ✅ CORRECT USE OF LAMBDA — single expression, used once, inline at the call site # The key function is self-explanatory. No def required, no namespace pollution. top_scorers = sorted(users, key=lambda user: user["score"], reverse=True) print("Top scorers:", [u["username"] for u in top_scorers]) # ✅ CORRECT USE OF LAMBDA — sorting by a derived tuple key, still one expression by_plan_then_score = sorted( users, key=lambda user: (user["plan"], -user["score"]) ) print("By plan then score:", [(u["plan"], u["username"]) for u in by_plan_then_score]) print() # ✅ CORRECT USE OF DEF — complex predicate, multiple conditions, needs documentation # This logic has business meaning that deserves to be named, tested, and documented. # Burying it in a lambda would make it untestable and undiscoverable. def is_eligible_for_beta(user: dict) -> bool: """ A user qualifies for beta access if they are an adult (18+), have a verified account, and have achieved a quality score above 70. Free plan users are excluded from this cohort regardless of score. """ return ( user["age"] >= 18 and user["verified"] and user["score"] > 70 and user["plan"] != "free" ) eligible_users = list(filter(is_eligible_for_beta, users)) print("Eligible for beta:", [u["username"] for u in eligible_users]) print() # ❌ ANTI-PATTERN — forcing multi-condition logic into a lambda # Same output, but zero readability benefit. Cannot be documented, cannot be unit tested # by name, and produces a '<lambda>' traceback if it raises a KeyError. bad_filter = list(filter( lambda u: u["age"] >= 18 and u["verified"] and u["score"] > 70 and u["plan"] != "free", users )) print("Same result, worse code:", [u["username"] for u in bad_filter]) print() # ── THE LATE BINDING TRAP — the most common lambda bug in production ── print("--- Late binding demonstration ---") # WRONG: all lambdas see the final value of i after the loop completes bad_lambdas = [lambda: i for i in range(5)] print("Without binding (WRONG):", [f() for f in bad_lambdas]) # [4, 4, 4, 4, 4] # CORRECT: i=i captures the current value at definition time via default arg good_lambdas = [lambda i=i: i for i in range(5)] print("With binding (CORRECT): ", [f() for f in good_lambdas]) # [0, 1, 2, 3, 4] print() # Realistic production scenario: building per-user report generators # The late binding trap is easy to hit when the loop variable is meaningful user_ids = ["usr_101", "usr_102", "usr_103"] # WRONG — every report generator will fetch usr_103's data bad_generators = [lambda: f"Generating report for {uid}" for uid in user_ids] print("Bad generators (all same):", [g() for g in bad_generators]) # CORRECT — each generator captures its own uid good_generators = [lambda uid=uid: f"Generating report for {uid}" for uid in user_ids] print("Good generators (distinct):", [g() for g in good_generators]) print() # ── FUNCTOOLS.PARTIAL AS AN ALTERNATIVE TO LAMBDA ── # For some cases, functools.partial is more readable than lambda import functools def apply_rate(value: float, rate: float) -> float: """Apply a multiplier rate to a value.""" return round(value * rate, 2) prices = [10.00, 25.00, 50.00, 100.00] # Lambda approach — fine, readable with_tax_lambda = list(map(lambda p: apply_rate(p, 1.08), prices)) # functools.partial approach — arguably clearer about what is being fixed apply_tax = functools.partial(apply_rate, rate=1.08) with_tax_partial = list(map(apply_tax, prices)) print("With tax (lambda): ", with_tax_lambda) print("With tax (partial): ", with_tax_partial) # identical output
By plan then score: [('enterprise', 'carol_dev'), ('free', 'eve_ml'), ('free', 'beta_tester'), ('pro', 'alex_92'), ('pro', 'dan_h')]
Eligible for beta: ['alex_92', 'carol_dev']
Same result, worse code: ['alex_92', 'carol_dev']
--- Late binding demonstration ---
Without binding (WRONG): [4, 4, 4, 4, 4]
With binding (CORRECT): [0, 1, 2, 3, 4]
Bad generators (all same): ['Generating report for usr_103', 'Generating report for usr_103', 'Generating report for usr_103']
Good generators (distinct): ['Generating report for usr_101', 'Generating report for usr_102', 'Generating report for usr_103']
With tax (lambda): [10.8, 27.0, 54.0, 108.0]
With tax (partial): [10.8, 27.0, 54.0, 108.0]
| Feature / Aspect | lambda | def |
|---|---|---|
| Syntax form | Single expression, implicit return — lambda params: expression | Full block with explicit return — def name(params): ... return value |
| Name in tracebacks | Shows as '<lambda>' — useless in production debugging; all lambdas look identical | Shows the actual function name — immediately locatable in the source file |
| Name in error monitoring | All lambda errors group under '<lambda>' in tools like Sentry, Datadog — error trends per function are invisible | Each function groups under its own name — error rates per function are trackable |
| Docstrings | Not supported — cannot document intent, parameters, or return value | Fully supported — the standard way to document what a function does and why |
| Type hints | Not supported — IDEs and type checkers cannot assist with lambda parameter types | Fully supported — mypy, pyright, and IDE tooling work correctly |
| Multi-statement logic | Impossible — SyntaxError on any statement inside a lambda body | Fully supported — if/elif/else, for, while, try/except all valid |
| Unit testability | Technically possible but awkward — you must import the surrounding function and extract the lambda | First-class — import the function by name and test it in isolation |
| Reusability | Discouraged — if you assign it to a variable you should be using def instead | Designed for reuse across the module and across the codebase |
| Late binding risk | High in loops — capturing loop variables by reference is the most common lambda bug in production | Same risk in nested functions, but the pattern is less common and more visible in code review |
| PEP 8 stance | Avoid assigning to a variable — 'Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier' | The universal standard for named, reusable, documentable functions — no caveats |
| Best used for | Inline key functions for sorted(), quick transforms for map(), simple predicates for filter() — all unnamed and used exactly once | Any function you will call more than once, test independently, document, or that needs more than a single expression |
🎯 Key Takeaways
- A lambda is syntactic sugar for a single-expression anonymous function — Python compiles it to the exact same bytecode as an equivalent def, so there is no performance difference between them. Anyone who tells you otherwise has not checked the bytecode.
- Lambdas belong inline at call sites for
sorted(),map(), andfilter()where the logic is a single readable expression used exactly once. The moment you assign a lambda to a variable, name it, or need more than one expression, def is the correct choice without exception. - Assigning a lambda to a variable is an explicit PEP 8 anti-pattern — if it has a name, it deserves def, because def gives you a real name in tracebacks, docstring support, type hint support, and per-function error grouping in monitoring tools.
- The loop-variable late binding trap is the most dangerous lambda bug in production — all lambdas in a loop see the loop variable's final value, not the value at the time each lambda was created. Fix it with default argument binding: lambda i=i: ... And add flake8-bugbear rule B023 to your linter so the CI pipeline catches it automatically.
⚠ Common Mistakes to Avoid
Interview Questions on This Topic
- QWhat is the practical difference between a lambda function and a def function in Python, and when would you choose one over the other?JuniorReveal
- QCan you explain the late binding closure problem with lambdas inside loops, and show how you would fix it?Mid-levelReveal
- QWhy does PEP 8 recommend against using lambda expressions that are assigned to a variable, even though it works perfectly fine technically?Mid-levelReveal
- QHow does functools.partial relate to lambda, and when would you prefer one over the other?SeniorReveal
Frequently Asked Questions
Can a Python lambda function have multiple lines?
No. A lambda is restricted to a single expression — no statements, no newlines, no assignments. The one-expression limit is not a temporary limitation waiting to be removed; it is a deliberate design boundary that enforces the use case lambdas are meant for: compact, readable, throwaway logic at a call site.
If you need multiple lines of logic, use a def function. Trying to simulate multi-line behavior by chaining expressions with semicolons or nesting function calls produces code that is harder to read than the def it was avoiding. The three extra lines of a def function are not overhead — they are the signal that this logic is complex enough to deserve a name, a docstring, and a test.
Is a lambda function faster than a def function in Python?
No — there is no meaningful performance difference. Python compiles both to the same underlying bytecode. You can verify this by running 'import dis; dis.dis(lambda x: x*2)' and comparing it to the equivalent def's bytecode — they are functionally identical at the bytecode level.
Any micro-benchmark difference you might measure is noise from timing overhead, not from any difference in the lambda versus def execution path. Choose between them based on readability and reusability, never on performance. If performance of a function call is genuinely critical, the solution is a different algorithm or a compiled extension — not switching from def to lambda.
Why can't I use an if statement inside a lambda?
Because if is a statement in Python, not an expression. Lambdas are restricted to expressions — constructs that evaluate to a single value. Statements execute actions; expressions produce values. The lambda body must produce a value, so only expressions are permitted.
What you can use is the conditional expression — the ternary operator — which is an expression that produces a value: 'lambda score: "pass" if score >= 50 else "fail"'. That is an expression that evaluates to one of two strings, so it is legal inside a lambda.
For anything more complex than a single conditional — nested conditions, chained elif branches, conditions with side effects — refactor to a def function. The readability improvement will be immediate and everyone who reads your code will thank you.
When should I use functools.partial instead of a lambda?
Use functools.partial when you are partially applying a named function — fixing some of its arguments to create a specialized version — and you want the original function's name to be visible in tracebacks and debugging tools.
For example, if you have 'def apply_rate(value, rate): return round(value * rate, 2)' and you want a tax-specific version, 'apply_tax = functools.partial(apply_rate, rate=1.08)' carries the name 'apply_rate' into any traceback involving apply_tax, whereas 'apply_tax = lambda v: apply_rate(v, rate=1.08)' gives you '<lambda>'.
Use lambda when the transformation is genuinely a new anonymous computation that does not reduce to partially applying an existing named function. Both are valid tools — the key distinction is whether there is an existing named function being specialized (reach for partial) or new inline logic being expressed (reach for lambda).
Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.