Homoiconic Python

What this project actually is

  • Multiple commenters note the project is essentially “Lisp in Python,” not “homoiconic Python.”
  • Some expected Python’s native syntax/AST to be directly manipulable; instead, it’s an interpreter for a Lisp-like language written in Python.
  • Debate on homoiconicity:
    • One view: it means the language is implemented in itself.
    • Another: it means code is a first-class data structure that can be constructed, inspected, and evaluated at runtime, regardless of implementation language.
  • Some doubt that truly homoiconic Python is possible without Python syntax being composed of native data structures evaluated directly.

Related languages and tools

  • Suggestions for “Python-like scripting Lisps” or Lisp-on-Python:
    • Hy, Basilisp (Clojure-style lisps targeting Python).
    • Janet (fast, embeddable, Lua-style VM).
    • Ciel (batteries-included Common Lisp “scripting” setup).
    • Rhombus (Python-ish surface syntax with Racket-style macros).
  • Other experiments: js-lisp (Lisp in JS), fakelisp (Lisp-like tuples in Python), yamlscript (“program in YAML”), Binary Lambda Calculus in Python, and a “homoiconic Java” DSL.

Lisp REPL, debugging, and error handling vs Python

  • Several comments praise Common Lisp’s REPL-driven workflow and debugging:
    • Ability to recompile and patch live code, inspect and modify stack frames, and resume execution via restarts.
    • Conditions/restarts separate error detection, handler choice, and recovery strategy, often allowing interactive continuation.
  • In contrast, Python typically unwinds the stack on exceptions; state at the throw site is lost after unwinding.
  • Some point out Python can still break into debuggers at exceptions and inspect locals; tools like py-spy, pystack, cpython-lldb, and periodic checkpointing (e.g., Joblib) are suggested.
  • Consensus: long-running Python jobs should persist intermediate state; relying on live introspection alone is risky.

Expressiveness, macros, and readability

  • Many admire Lisps’ expressiveness, macros, and historical influence; others argue that this freedom often leads to unreadable “abominations.”
  • One view: languages like Go or Python intentionally restrict expressiveness (no rich macros, clunky lambdas) to limit how “clever” or non-idiomatic code can become.
  • Counterpoints:
    • Any language can host terrible code; organization and developers matter more.
    • Lisp style guides explicitly caution against overusing macros; they are powerful but should be written sparingly.
    • Macros can improve readability by creating concise domain-specific layers (e.g., object systems) that hide lower-level complexity.

Types and “taming” Lisp

  • For those worried about large Lisp codebases becoming hard to reason about:
    • Typed Racket and Shen are offered as strongly-typed Lisps.
    • Dylan and Common Lisp (with compiler type declarations and warnings, especially in SBCL) are mentioned as Lisps with useful type systems or type checking support.