{"id":22753311,"url":"https://github.com/hsfzxjy/lambdex","last_synced_at":"2025-10-09T11:08:39.071Z","repository":{"id":57456079,"uuid":"326411742","full_name":"hsfzxjy/lambdex","owner":"hsfzxjy","description":"Write complicated anonymous functions beyond lambdas in Python.","archived":false,"fork":false,"pushed_at":"2024-03-14T00:47:39.000Z","size":331,"stargazers_count":81,"open_issues_count":2,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-07-28T16:37:37.180Z","etag":null,"topics":["anonymous-functions","compiler","formatter","lambdas","languages","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hsfzxjy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-01-03T13:19:46.000Z","updated_at":"2024-11-28T16:34:54.000Z","dependencies_parsed_at":"2022-09-04T04:21:28.372Z","dependency_job_id":null,"html_url":"https://github.com/hsfzxjy/lambdex","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/hsfzxjy/lambdex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hsfzxjy%2Flambdex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hsfzxjy%2Flambdex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hsfzxjy%2Flambdex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hsfzxjy%2Flambdex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hsfzxjy","download_url":"https://codeload.github.com/hsfzxjy/lambdex/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hsfzxjy%2Flambdex/sbom","scorecard":{"id":470747,"data":{"date":"2025-08-11","repo":{"name":"github.com/hsfzxjy/lambdex","commit":"64fae676063d16af4f861441e825740c5696001d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-19T13:50:44.126Z","repository_id":57456079,"created_at":"2025-08-19T13:50:44.126Z","updated_at":"2025-08-19T13:50:44.126Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271420155,"owners_count":24756491,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-21T02:00:08.990Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anonymous-functions","compiler","formatter","lambdas","languages","python"],"created_at":"2024-12-11T06:10:10.535Z","updated_at":"2025-10-09T11:08:34.035Z","avatar_url":"https://github.com/hsfzxjy.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 style=\"text-align: center\"\u003elambdex\u003c/h1\u003e\n\n[![PyPI version fury.io](https://badge.fury.io/py/pylambdex.svg)](https://pypi.python.org/pypi/pylambdex/) [![PyPI pyversions](https://img.shields.io/pypi/pyversions/pylambdex.svg)](https://pypi.python.org/pypi/pylambdex/) [![PyPI status](https://img.shields.io/pypi/status/pylambdex.svg)](https://pypi.python.org/pypi/pylambdex/) [![Build Status](https://travis-ci.com/hsfzxjy/lambdex.svg?branch=master)](https://travis-ci.com/hsfzxjy/lambdex) [![GPLv3 license](https://img.shields.io/badge/License-GPLv3-blue.svg)](http://perso.crans.org/besson/LICENSE.html)\n\n**lambdex** allows you to write multi-line anonymous function expression (called a _lambdex_) in an idiomatic manner. Below is a quick example of a recursive Fibonacci function:\n\n```python\ndef_(lambda n: [\n    if_[n \u003c= 0] [\n        raise_[ValueError(f'{n} should be positive')]\n    ],\n    if_[n \u003c= 2] [\n        return_[1]\n    ],\n    return_[callee_(n - 1) + callee_(n - 2)]\n])(10)  # 55\n```\n\nCompared with ordinary lambda, which only allows single expression as body, lambdex may contain multiple \"statements\" in analogue to imperative control flows, whilst does not violate the basic syntax of Python.\n\n\u003cdetails open\u003e\n\u003csummary\u003e \u003cem\u003eTable of Content\u003c/em\u003e\u003c/summary\u003e\n\n- [More about lambdex](#more-about-lambdex)\n- [WHAT'S NEW](./CHANGELOG.md)\n- [Installation \u0026 Usage](#installation--usage)\n- [**Language Features**](#language-features)\n  - [Parameters](#parameters)\n  - [Variable assignment](#variable-assignment)\n  - [Augmented assignment](#augmented-assignment)\n  - [Conditional statement](#conditional-statement)\n  - [Looping](#looping)\n  - [With statement](#with-statement)\n  - [Try statement](#try-statement)\n  - [Yield statement](#yield-statement)\n  - [Async and Await](#async-and-await)\n  - [Miscellaneous](#miscellaneous)\n  - [Nested lambdexes](#nested-lambdexes)\n  - [Recursion](#recursion)\n  - [Renaming functions](#renaming-functions)\n- [Detailed Compile-time and Runtime Error](#detailed-compile-time-and-runtime-error)\n- [**EDGE CASES**](#edge-cases)\n  - [Running in an REPL](#running-in-an-repl)\n  - [Declaration Disambiguity](#declaration-disambiguity)\n- [**Runtime Efficiency**](#runtime-efficiency)\n  - [Bytecode Caching](#bytecode-caching)\n  - [Bytecode Optimization at Function Level](#bytecode-optimization-at-function-level)\n  - [Bytecode Optimization at Module Level](#bytecode-optimization-at-module-level)\n- [**Customization**](#customization)\n  - [Keyword and Operator Aliasing](#keyword-and-operator-aliasing)\n  - [Language Extension](#language-extension)\n- [**Code Formatting**](#code-formatting)\n  - [Standalone lambdex formatter](#standalone-lambdex-formatter)\n  - [Lambdex formatter as post-processor](#lambdex-formatter-as-post-processor)\n  - [Mocking existing formatter executable](#mocking-existing-formatter-executable)\n- [Known Issues \u0026 Future](#known-issues--future)\n- [Q \u0026 A](#q--a)\n- [License](#license)\n\u003c/details\u003e\n\n## More about lambdex\n\nAn anonymous function is a function definition that is not bound to an identifier, which is ubiquitous in most languages with first-class functions. The language feature could be handy for logics that appear to be short-term use, and therefore adopted widely in some functional programming paradigms.\n\nPython provides `lambda \u003carg\u003e: \u003cexpr\u003e` for such purpose. Lambdas are good for simple functionalities, but appear limited if logical complexity goes up. Consequently, higher-order functions (e.g., decorators) are often implemented as nested named functions, which is not concise enough.\n\n**lambdex** as an experimental complement to lambdas, aims to provide a syntax similar to Python for anonymous functions. The syntax itself is built upon valid Python expressions, and therefore requires no modification to the interpreter. This package transpiles lambdexes into Python bytecodes at runtime, and therefore ensures the efficiency.\n\n## Installation \u0026 Usage\n\nYou can install **lambdex** from PyPI by\n\n```bash\npip install pylambdex\n```\n\nor from Github by\n\n```bash\npip install git+https://github.com/hsfzxjy/lambdex\n```\n\nTo use lambdex, a simple import is required:\n\n```python\nfrom lambdex import def_\n\nmy_sum = def_(lambda a, b: [\n    return_[a + b]\n])\n```\n\nThat's it! You don't even need to import other keywords such as `return_`.\n\n## Language Features\n\nWe are going to explore a wide range of features supported by **lambdex** in the following sections.\n\n### Parameters\n\nThe parameter declaration of lambdexes appears after the `lambda`. The syntax supports most variants of declaration just as ordinary functions.\n\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\n# ordinary parameters\ndef_(lambda a, b: [...])\n\n# parameters with default values\ndef_(lambda a, b=1: [...])\n\n# starred arguments\ndef_(lambda *args, **kwargs: [...])\n\n# keyword-only arguments\ndef_(lambda *, a, b: [...])\n\n# positional-only arguments (Python 3.8+)\ndef_(lambda a, b, /: [...])\n```\n\n\u003c/details\u003e\n\n### Variable assignment\n\nLambdexes use `\u003c` instead of `=` for assignments, since `=` in Python is valid only in statements.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    foo \u003c \"bar\",\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    foo = \"bar\"\n```\n\n\u003c/details\u003e\n\n`\u003c` is chainable like ordinary `=`.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    foo \u003c baz \u003c \"bar\",\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    foo = baz = \"bar\"\n```\n\n\u003c/details\u003e\n\nNote that `\u003c` has a higher precedence than `not`, `and`, `or` and `if...else...`. R-value with these operators should be enclosed by parentheses:\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    foo \u003c (a or b and not c),\n    foo \u003c (a if cond else b),\n])\n```\n\n\u003c/details\u003e\n\nTuple destruction is also supported:\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    (a, b) \u003c (b, a),\n    (a, *rest, c) \u003c [1, 2, 3],\n])\n```\n\n\u003c/details\u003e\n\nIn Python 3.8 or above, the walrus operator `:=` might also be used. But be careful that Python enforces parentheses around `:=` in many cases.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    foo := \"bar\",           # OK\n    foo := baz := \"bar\",    # syntax error\n    foo := (baz := \"bar\"),  # OK\n    if_[condition] [\n        foo := \"bar\",       # syntax error\n        (foo := \"bar\"),     # OK\n    ]\n])\n```\n\n\u003c/details\u003e\n\n### Augmented assignment\n\nThe augmented assignments are written as `[op]_\u003c`, for example, `+_\u003c` for `+=`. The snippet below illustrates all supported augmented assignments:\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    a +_\u003c 1,\n    a -_\u003c 1,\n    a *_\u003c 1,\n    a /_\u003c 1,\n    a //_\u003c 1,\n    a @_\u003c 1,\n    a %_\u003c 1,\n    a \u003c\u003c_\u003c 1,\n    a \u003e\u003e_\u003c 1,\n    a **_\u003c 1,\n    a \u0026_\u003c 1,\n    a |_\u003c 1,\n    a ^_\u003c 1,\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    a += 1\n    a -= 1\n    a *= 1\n    a /= 1\n    a //= 1\n    a @= 1\n    a %= 1\n    a \u003c\u003c= 1\n    a \u003e\u003e= 1\n    a **= 1\n    a \u0026= 1\n    a |= 1\n    a ^= 1\n```\n\n\u003c/details\u003e\n\n### Conditional statement\n\nLambdexes use `if_`, `elif_` and `else_` for conditional control flows.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    if_[condition_1] [\n        ...,\n    ].elif_[condition_2] [\n        ...,\n    ].else_[\n        ...,\n    ]\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    if condition_1:\n        ...\n    elif condition_2:\n        ...\n    else:\n        ...\n```\n\n\u003c/details\u003e\n\n### Looping\n\nLambdexes support the two kinds of looping by keywords `for_` and `while_`.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    # for...in...else...\n    for_[i in range(10)] [\n        print_(i),\n    ].else_[\n        print(\"the optional else clause\"),\n    ],\n\n    # while...else...\n    while_[condition] [\n        ...,\n    ].else_[\n        print(\"the optional else clause\"),\n    ]\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    # for...in...else...\n    for i in range(10):\n        print(i)\n    else:\n        print(\"the optional else clause\")\n\n    # while...else...\n    while condition:\n        print(\"the optional else clause\")\n```\n\n\u003c/details\u003e\n\n`break_` and `continue_` are also supported.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    for_[i in range(10)] [\n        if_[i \u003e= 5] [\n            break_\n        ].else_[\n            continue_\n        ]\n    ]\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    for i in range(10):\n        if i \u003e= 5:\n            break\n        else:\n            continue\n```\n\n\u003c/details\u003e\n\n### With statement\n\nWith statements are supported by the `with_` keyword. The optional `as` is written using `\u003e`.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    # simple `with`\n    with_[open(\"foo\")] [\n        ...\n    ]\n\n    # `with` with `as`\n    with_[open(\"foo\") \u003e fd] [\n        ...\n    ]\n\n    # multiple `with`\n    with_[open(\"foo\"), open(\"bar\") \u003e fd] [\n        ...\n    ]\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    # simple `with`\n    with open(\"foo\"):\n        ...\n\n    # `with` with `as`\n    with open(\"foo\") as fd:\n        ...\n\n    # multiple `with`\n    with open(\"foo\"), open(\"bar\") as fd:\n        ...\n```\n\n\u003c/details\u003e\n\n### Try statement\n\nThe ordinary try statements are supported by keywords `try_`, `except_`, `else_` and `finally_`.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    try_[\n        ...\n    ].except_[RuntimeError] [\n        ...\n    ].except_[\n        ...\n    ].else_[\n        ...\n    ].finally_[\n        ...\n    ]\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    try:\n        ...\n    except RuntimeError:\n        ...\n    except:\n        ...\n    else:\n        ...\n    finally:\n        ...\n```\n\n\u003c/details\u003e\n\nThe optional `as` in `except` clause is written as `\u003e`.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    try_[\n        ...\n    ].except_[RuntimeError \u003e e] [\n        ...\n    ]\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    try:\n        ...\n    except RuntimeError as e:\n        ...\n```\n\n\u003c/details\u003e\n\n### Yield statement\n\nThe `yield` and `yield...from...` structures are supported by keywords `yield_` and `yield_from_`. A lambdex contains one or more `yield_` or `yield_from_` will automatically become a generator.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    yield_[1, 2],\n    yield_from_[range(3, 10)],\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    yield (1, 2)\n    yield from range(3, 10)\n```\n\n\u003c/details\u003e\n\n`yield_` itself is an expression, and thus can appear in anywhere an expression is allowed. Note that parentheses might be added.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    a \u003c (yield_),\n\n    if_[a \u003c (yield_)] [...],\n\n    with_[(yield_) \u003e cm] [...],\n\n    for_[i in (yield_)] [...]\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    a = (yield)\n    if a \u003c (yield): ...\n    with (yield) as cm: ...\n    for i in (yield): ...\n```\n\n\u003c/details\u003e\n\n### Async and Await\n\n**lambdex** supports coroutines by keywords `async_def_`, `async_for_`, `async_with_` and `await_`.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\nfrom lambdex import async_def_\nasync_def_(lambda: [\n    async_for_[a in b] [ ... ],\n    async_with_[a \u003e b] [ ... ],\n    await_[a],\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\nasync def anonymous():\n    async for a in b: ...\n    async with a as b: ...\n    await a\n```\n\n\u003c/details\u003e\n\n### Miscellaneous\n\nLambdexes support some other keywords in Python too.\n\nThe `return_` is analogue to keyword `return`.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    return_[a, b]\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    return a, b\n```\n\n\u003c/details\u003e\n\nThe `pass_` is analogue to keyword `pass`.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    pass_\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    pass\n```\n\n\u003c/details\u003e\n\nThe `raise_` is analogue to keyword `raise`.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    try_[\n        raise_[RuntimeError]\n    ].except_[ValueError \u003e e] [\n        # the optional from clause\n        raise_[RuntimeError].from_[e]\n    ].except_[\n        # the bare raise\n        raise_\n    ]\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    try:\n        raise RuntimeError\n    except ValueError as e:\n        raise RuntimeError from e\n    except:\n        raise\n```\n\n\u003c/details\u003e\n\nThe `del_` is analogue to keyword `del`.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    a \u003c [1, 2],\n    del_[a[0], a],\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    a = [1, 2]\n    del a[0], a\n```\n\n\u003c/details\u003e\n\nThe `global_` and `nonlocal_` are analogue to keywords `global` and `nonlocal`.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    global_[a],\n\n    return_[def_(lambda: [\n        nonlocal_[a],\n    ])]\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    global a\n\n    def _inner():\n        nonlocal a\n\n    return _inner\n```\n\n\u003c/details\u003e\n\n### Nested lambdexes\n\nLambdexes can be nested to construct more complicated logics. Lambdexes respect the nested scoping rules in Python, i.e., inner lambdex captures names defined in its parent scopes. For example, we can define [IIFE](https://en.wikipedia.org/wiki/Immediately_invoked_function_expression) like in JavaScript to capture looping variables.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\n# without IIFE\narr = []\nfor i in range(10):\n    arr.append(def_(lambda: [\n        print(i)\n    ]))\nfor func in arr:\n    func()  # print \"9\" x10 times\n\n# with IIFE\narr = []\nfor i in range(10):\n    func = def_(lambda i: [\n        return_[def_(lambda: [\n            print(i)\n        ])]\n    ])(i)\n    arr.append(func)\nfor func in arr:\n    func()  # print from \"0\" to \"9\"\n```\n\n\u003c/details\u003e\n\n### Recursion\n\nOne can always access the current lambdex itself via `callee_` within a lambdex. The feature is quite handy since you don't need to assign a lambdex to a name for doing recursion.\n\n```python\n# Summing from 1 to 10\n(def_(lambda n: [\n    if_[n == 1] [\n        return_[n]\n    ],\n    return_[callee_(n - 1) + n]\n]))(10)\n```\n\nNote that `callee_` within an inner lambdex repesents itself instead of the outer one:\n\n```python\nf = def_(lambda: [\n    inner \u003c def_(lambda: [\n        return_[callee_]\n    ]),\n    return_[inner, inner(), callee_]\n])\nf1, f2, f3 = f()\nf1 is f2  # True\nf3 is f   # True\n```\n\n### Renaming functions\n\nA lambdex may have an optional name which uses the syntax `def_.\u003cname\u003e(...)`. For example:\n\n```python\ndef_.one_divided_by_zero(lambda: [\n    1 / 0,\n])\n```\n\nThe name is used for improving readability of a traceback when an error occurs. For example, the function above yields an exception:\n\n```\nTraceback (most recent call last):\n  File \"test.py\", line 6, in \u003cmodule\u003e\n    f()\n  File \"test.py\", line 3, in one_divided_by_zero\n    1 / 0,\nZeroDivisionError: division by zero\n```\n\nThe last frame of the traceback displays a name `one_divided_by_zero` instead of some `anonymous_xxx` by default.\n\nBut be careful that **this feature does not imply any name bindings,** that is, you can not use the name as a variable to reference a function:\n\n```python\ndef_.one_divided_by_zero(lambda: [\n    1 / 0,\n    one_divided_by_zero,  # NameError\n])\none_divided_by_zero  # NameError\n\ndef_(lambda: [\n    def_.inner_func(lambda: [\n        inner_func  # NameError\n    ]),\n    inner_func,  # NameError\n])\n```\n\n## Detailed Compile-time and Runtime Error\n\n**lambdex** preserves information of source code such as line number or token offsets. The information are used to provide detailed messages when error occurs.\n\nFor example, the following code mis-types else\\_ as els\\_:\n\n```python\nfrom lambdex import def_\n\ndef_(lambda: [\n    if_[cond][\n        ...\n    ].els_[\n        ...\n    ]\n])\n```\n\nwhich will yield a SyntaxError at compile-time:\n\n```\nTraceback (most recent call last):\n  File \"demo.py\", line 3, in \u003cmodule\u003e\n    def_(lambda: [\n  --- Traceback omitted ---\n  File \"demo.py\", line 6\n    ].els_[\n         ^\nSyntaxError: expect 'else_' or 'elif_'\n```\n\nErrors at runtime can also be located to corresponding lines. For example:\n\n```python\nfrom lambdex import def_\n\ndef_(lambda: [\n    def_(lambda: [\n        a \u003c 1 / 0,\n        return_[a]\n    ])()\n])()\n```\n\nwill yield:\n\n```\nTraceback (most recent call last):\n  File \"demo.py\", line 3, in \u003cmodule\u003e\n    def_(lambda: [\n  File \"demo.py\", line 4, in anonymous_d598829c\n    def_(lambda: [\n  File \"demo.py\", line 5, in anonymous_dc2006c1\n    a \u003c 1 / 0,\nZeroDivisionError: division by zero\n```\n\n## EDGE CASES\n\nWe are going to discuss several edge cases in this section.\n\n### Running in an REPL\n\nIf you are using an interactive environment (REPL), like IDLE or IPython, you should import the keywords from `lambdex.repl`:\n\n```python\n\u003e\u003e\u003e from lambdex.repl import def_\n\u003e\u003e\u003e my_sum = def_(lambda a, b: [\n...     return_[a + b]\n... ])\n...\n\u003e\u003e\u003e my_sum(1, 2)\n3\n```\n\nThe statement should be executed **at the beginning** to ensure that corresponding patching stuff is enabled.\n\nCurrently **lambdex** has been well tested on 3 REPL environments: the built-in Python REPL, IDLE and IPython (Jupyter). Other REPL may or may not be supported.\n\n### Declaration Disambiguity\n\nSuppose you are running the following code:\n\n```python\nf1, f2 = def_(lambda a, b: [return_[a + b]]), def_(lambda a, b: [return_[a * b]])\n```\n\nThe code yields an exception `SyntaxError: ambiguious declaration 'def_'`.\n\nWhat's going on here? The problem is that **there are more than one lambdexes defined on the same line**. Since CPython provides no effective way but a line number for locating a given lambda, the lambdex compiler fails to obtain the source code of the lambda in this case. A workaround is to prepend an identifier after `def_` of lambdex:\n\n```python\nf1, f2 = def_.f1(lambda a, b: [return_[a + b]]), def_.f2(lambda a, b: [return_[a * b]])\n```\n\nWith this, the compiler can now tell them from each other.\n\nIn the example above, it's not necessary to add identifier for both lambdexes. The following is also acceptable, as long as their declarations are different:\n\n```python\nf1, f2 = def_.f1(lambda a, b: [return_[a + b]]), def_(lambda a, b: [return_[a * b]])\n```\n\n## Runtime Efficiency\n\nThe transpilation procedure could be very time-consuming, and thus degrades the runtime efficiency. To solve the problem, **lambdex** itself provides several mechanisms on different levels for optimizing the bytecodes.\n\n### Bytecode Caching\n\nBy default, **a lambdex defined at a specific location will be compiled only once**. The code object of compiled lambdex will be cached and reused in the future execution. Such mechanism applies to lambdexes defined either in a looping or as an inner function, i.e., the two lambdexes below would be compiled only once:\n\n```python\ns = 0\nfor i in range(10000):\n    def_(lambda: [          # compiled at i = 0\n        global_[s],\n        s \u003c s + i,\n    ])()\n\ndef foo(i):\n    return def_(lambda: [   # compiled at the first time `foo()` executed\n        global_[s],\n        s \u003c s + i,\n        return_[s],\n    ])\n```\n\n### Bytecode Optimization at Function Level\n\nBytecode caching reduces most of the redundant and heavy jobs, but still has some overhead -- the core of **lambdex** needs to update some metadata (such as closure cellvars) every time `def_` was executed. For example, one may find that the snippet below costs too much time to run (like \u003e3s):\n\n```python\nfrom lambdex import def_\ns = 0\ndef sum():\n    n = 1000000\n    for i in range(n):\n        adder = def_(lambda: [\n            global_[s],\n            s \u003c s + i\n        ])\n        adder()\n    assert s == n * (n - 1) / 2\nsum()\n```\n\nTo optimize, one can use the `@asmopt` decorator:\n\n```python\nfrom lambdex import def_, asmopt\ns = 0\n@asmopt\ndef sum():\n    n = 1000000\n    for i in range(n):\n        adder = def_(lambda: [\n            global_[s],\n            s \u003c s + i\n        ])\n        adder()\n    assert s == n * (n - 1) / 2\nsum()\n```\n\nThe running time will now reduce to ~0.3s, which is x10 faster and the same as using ordinary functions. The magical `@asmopt` eliminates `def_` calling and directly stores compiled lambdex on `sum`. It is worth to note that `@asmopt` should always be the innermost decorator.\n\n### Bytecode Optimization at Module Level\n\nThe previous mechanism only applies to lambdexes within some functions, and still has some overhead at module initialization phase. Can we do better? Absolutely yes! One can use the `# lambdex: modopt` directive to optimize the whole module, and persist the optimized bytecode into corresponding .pyc files.\n\n```python\n# modopt_demo.py\n\n# the directive could be placed everywhere\n# lambdex: modopt\nfrom lambdex import def_\ns = 0\nn = 1000000\nfor i in range(n):\n    adder = def_(lambda: [\n        global_[s],\n        s \u003c s + i\n    ])\n    adder()\nassert s == n * (n - 1) / 2\nsum()\n```\n\n```bash\n$ time python3 -m modopt_demo  #  \u003e 3s: 1st time, unoptimized\n$ time python3 -m modopt_demo  # ~0.3s: 2nd time and later, optimized\n$ time python3 -m modopt_demo  # ~0.3s\n```\n\nOptimized bytecodes will be invalidated when the source file is edited, but be available in the following executions. Thus you can see that the script costs rather long time at first, but becomes efficient afterwards.\n\nIt's worth to note that such mechanism is unavailable when you run the file as a script via `python3 modopt_demo.py`, which is a limitation of CPython. In other cases, such as using `python3 -m modopt_demo` or importing as a module in other files, the mechanism works well.\n\n## Customization\n\nUsers are able to customize some aspects of **lambdex**, in order to fit their preference.\n\n### Keyword and Operator Aliasing\n\nIf you don't like the default keywords or operators, **lambdex** allows you to use alternative ones. See the [doc](./docs/Customization.md#keyword-and-operator-aliasing) for detailed configuration.\n\n### Language Extension\n\n**lambdex** allows you to customize some of the syntax. For how to enable specific extension, please forward to the [doc](./docs/Customization.md#language-extension).\n\nCurrently the following ones are supported:\n\n---\n\n**await_attribute**\n\nWith this enabled, you can use Rust-style await expressions.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\nasync_def_(lambda: [\n    a.await_.b.await_.c,\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\nasync def anonymous():\n    (await (await a).b).c\n```\n\n\u003c/details\u003e\n\n---\n\n**implicit_return**\n\nWith this enabled, the last statement of a function body will be regarded as the return value.\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    1 + 1\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    return 1 + 1\n```\n\n\u003c/details\u003e\n\nBut be careful that this doesn't apply to assignments at the last:\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef_(lambda: [\n    a \u003c 1\n])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cem\u003eshow equivalent function\u003c/em\u003e\u003c/summary\u003e\n\n```python\ndef anonymous():\n    a = 1\n```\n\n\u003c/details\u003e\n\n## Code Formatting\n\nThe proposed lambdex syntax violates the convention of most code formatters. In order to keep the code tidy, this library provides a light-weight formatter **lxfmt** for lambdex syntax, which can either work standalonely or cooperate with existing formatters.\n\nHere's an example of what **lxfmt** does:\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\nfrom lambdex import def_\n\ndef f():\n    return def_.myfunc(  # comment1\n        lambda a, b:   [# comment2\n  if_[condition] [\n      f2 \u003c def_(lambda:[a+b]),\n      return_[f2],\n            ],try_[# comment3\n      body,\n  ].except_[Exception \u003e e] [\n      except_handler\n  ] # comment4\n  ,         ],# comment5\n        )\n```\n\n\u003c/details\u003e\n\n\u003cdetails open\u003e\n    \u003csummary\u003e\u003cem\u003eshow code\u003c/em\u003e\u003c/summary\u003e\n\n```python\nfrom lambdex import def_\n\n\ndef f():\n    return def_.myfunc(lambda a, b: [  # comment1\n        # comment2\n        if_[condition] [\n            f2 \u003c def_(lambda: [\n                a+b\n            ]),\n            return_[f2],\n        ],\n        try_ [  # comment3\n            body,\n        ].except_[Exception \u003e e] [\n            except_handler\n        ],  # comment4\n        # comment5\n    ])\n```\n\n\u003c/details\u003e\n\n### Standalone lambdex formatter\n\nThe usage of standalone **lxfmt** is shown below:\n\n```\nusage: lxfmt [-h] [-d | -i | -q] [-p] [files [files ...]]\n\nDefault formatter for lambdex\n\npositional arguments:\n  files           reads from stdin when no files are specified.\n\noptional arguments:\n  -h, --help      show this help message and exit\n  -d, --diff      print the diff for the fixed source\n  -i, --in-place  make changes to files in place\n  -q, --quiet     output nothing and set return value\n  -p, --parallel  run in parallel when formatting multiple files.\n```\n\nFor example, use `lxfmt -i file.py` to format in-place, or `lxfmt -d file.py` to show the difference before and after formatting.\n\n### Lambdex formatter as post-processor\n\n**lxfmt** can work as a post-processor of existing formatter, such as [yapf](https://github.com/google/yapf). One can specify a formatter backend by prepending `-- -b BACKEND` to the command. The overall usage is shown below:\n\n```\nusage: lxfmt [ARGS OF BACKEND] -- [-h] [-b BACKEND] [-e EXECUTABLE]\n\nLambdex formatter as a post-processor for specific backend\n\noptional arguments:\n  -h, --help            show this help message and exit\n  -b BACKEND, --backend BACKEND\n                        name of formatter backend (default: dummy)\n  -e EXECUTABLE, --executable EXECUTABLE\n                        executable of backend\n```\n\n**Note that `[ARGS OF BACKEND]` are the arguments fed to the specified backend.**\n\nFor example, to use **lxfmt** after **yapf**, with yapf style configuration at `~/.config/yapf/style`, one may use:\n\n```bash\nlxfmt file.py --style ~/.config/yapf/style -- -b yapf\n```\n\n_Currently **lxfmt** supports only yapf. Adapters for other formatters will be added in the future._\n\n### Mocking existing formatter executable\n\nThe `-- -b BACKEND` appears to be verbose, and sometimes you may want to alias the command of \"formatter backend + post-processor\" to save the typing work. The library provides another tool `lxfmt-mock` to do the job.\n\n```\nusage: lxfmt-mock [-h] [-r] BACKEND\n\nMock or reset specified formater backend\n\npositional arguments:\n  BACKEND      The backend to be mocked/reset\n\noptional arguments:\n  -h, --help   show this help message and exit\n  -r, --reset  If specified, the selected command will be reset\n```\n\nFor example, running `lxfmt-mock yapf`, the tool will search for and list out available yapf executables to be mocked:\n\n```bash\n$ lxfmt-mock yapf\n[?] Which one do you want to mock?:\n ❯ /home/me/.local/bin/yapf\n   /usr/data/anaconda3/bin/yapf\n```\n\nBy choosing a executable, e.g. `/home/me/.local/bin/yapf`, `/home/me/.local/bin/yapf \u003cargs\u003e` will become a shorthand for `lxfmt \u003cargs\u003e -- -b yapf -e /home/me/.local/bin/yapf`. The original executable will be stored at `/home/me/.local/bin/original_yapf`.\n\nTo reset a mocked executable, simply run `lxfmt-mock yapf -r` and choose from the list.\n\nMocking a formatter backend could be very useful when you want to enable lambdex code formatting in your IDE/editor. By mocking the executable your IDE/editor uses, you can enjoy the feature on the fly without modifying any settings.\n\n## Known Issues \u0026 Future\n\nCurrently lambdex doesn't support:\n\n1. type annotation\n2. `import` statements\n\nType annotation [1] and `import` statements [2] will not be supported.\n\nLambdexes also violate linters, which is inevitable.\n\nBesides, the upcoming versions will:\n\n- add style options for **lxfmt**\n\n, in order to provide a better developing experience.\n\n## Q \u0026 A\n\n**Why using brackets \"[]\" to enclose statement heads and bodies instead of parentheses \"()\"?**\n\nBrackets are easier to type than parentheses on most of the keyboards.\n\n---\n\n**Why using \"\u003c\" and \"\u003e\" for assignment and as?**\n\nThe design is from three considerations. _1)_ Comparators such as \"\u003c\", \"\u003c=\", \"\u003e\" or \"\u003e=\" [have lower precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence) than most of the other operators, thus allowing R-values without parentheses for most of the time; _2)_ in AST representation, chained comparators have a flat structure, which is easier to parse; _3)_ \"\u003c\" and \"\u003e\" visually illustrate the direction of data flows.\n\nThe preference of \"\u003c\" \"\u003e\" over \"\u003c=\" \"=\u003e\" is that the previous ones consume only one character and are easier to type.\n\n---\n\n**Why use configuration file based keyword and operator aliasing instead of a programmatic approach?**\n\nThe design is from two concerns.\n\n1. A programmatic approach may cause inconsistency at runtime, which is difficult for troubleshooting. For example, if one declares the aliasing in `mod/__init__.py` and uses the new keywords in `mod/A.py`, the aliasing works fine if `mod/A.py` imported as `mod.A`, but fails if run as a standalone script.\n2. The compiler and formatter should behave consistently when processing the same file. If a programmatic approach used, the formatter must apply semantic analysis to figure out the aliasing rules, which is far more complicated.\n\n---\n\n**Lambdex appears to be less readable than functions and will mess up my code. Why should I use it?**\n\nThe project is not to criticize the present design of Python, but an experimental attempt to provide alternative for the ones who need a better anonymous function expression. The need may be from a second language they are familiar with, or the paradigms they want to use.\n\n**lambdex** decides not to perform any modification on the interpreter, but build the new syntax upon existing Python syntax. The choice determines that keywords should be aliased and artifacts like \"[]\" would appear everywhere, which reduces the readability. To mitigate this, **lambdex** is paying effort to make the lambdex syntax resemble the Python syntax.\n\nIt is true that there's a trade-off between readability and functionality. The decision should depend on your own requirements.\n\n---\n\n**What's the magic behind lambdex?**\n\n`def_` or `def_.\u003cident\u003e` are actually callables, which take a lambda object as input, transpile it into an ordinary function and then return. The definition is in [lambdex.keywords](lambdex/keywords.py) module.\n\nThe transpilation process can be roughly separated into three stages.\n\nIn the first stage, we try to find the source code of given lambda object and parse it into AST. Source code searching is performed by [lambdex.utils.ast::ast_from_source](lambdex/utils/ast.py#L59), which is modified from _inspect.getsourcelines_ to work more robust on lambdas. The obtained source is parsed into AST, which then pattern-matched to locate the Lambda node. The entry of this stage is [lambdex.ast_parser::lambda_to_ast](lambdex/ast_parser.py#L43).\n\nIn the second stage, we traverse the AST of lambda object, replacing some node patterns with correponding Python statements, recursively building up the body of new function. Inner lambdexes are detached from where they lay, and become nested functions within the constructed body. This part is at [lambdex.compiler.dispatcher](lambdex/compiler/dispatcher.py) and [lambdex.compiler.rules](lambdex/compiler/rules.py).\n\nIn the last stage, we compile the new AST into code object, restore metadata (globals, closures, etc.) from the original lambda object, and wrap it by a Function object. Modification might be applied to AST to correct the compilation result, e.g., wrap AST in a dummy function to make specific names nonlocal instead of global. This is done in [lambdex.compiler.core::compile_lambdex](lambdex/compiler/core.py#L70). Bytecode caching also happens in this stage.\n\nFor better understanding, you may look into the source code and check the detailed implementation.\n\n## License\n\nCopyright (c) 2021 Jingyi Xie (hsfzxjy). Licensed under the [GNU General Public License version 3](https://opensource.org/licenses/GPL-3.0).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhsfzxjy%2Flambdex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhsfzxjy%2Flambdex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhsfzxjy%2Flambdex/lists"}