PureScript(especially PureScript-python) for what?
-
Simple and intuitive Python interop
-
Advanced type system
-
higher kinded types
-
higer rank types
-
functional dependencies
-
extensible records
-
data kinds
-
etc..
This is an extreme of being pragmatic, and makes decoupling and composition easier.
-
-
Excellent IDE, better type-driven programming experience, less of mental burden.
You understand what does "implicit type inference + auto-completion + real-time error highlighting + type constraints by advanced type system" mean?
-
Multiple back ends: JavaScript, Go/C++, Python, Kotlin, etc.
Currently many purescript libraries are supported, like
- prelude
- generics-rep(for
derivingtype classes likeShow,Generic, etc.) - console
- effect
- enums
- controls
- partial
- etc.
purescript-python has grown up to some degree with pretty nice availability.
After slightly modifying a JavaScript-like IR produced by the builtin compiler,
PureScript gets compiled to PySExpr and shall work since Python 3.5.
The reason why we generate the IR PySExpr instead of Python source code,
is for getting better cross-Python-version compatibility, Python-version-specific optimizations,
source code positioning for using existing Python debuggers in PureScript, and expression-first expressiveness. You could check out this reddit post for more details.
Given a PureScript module, not losing the generality, we abbreviate it as A.B.
After processing this module via the command
# `output` is the directory produced by the PureScript build tool `spago`.
pspy-blueprint --out-python aaa/bbb/output_top_dir --corefn-entry A.B --out-ffi-dep ffi-requires.txtCommand pspy-blueprint generates following directory tree(all __init__.py will be added later, but not in Haskell side):
- aaa/bbb/output_top_dir
- A
- B
- pure.py
- pure.zip.py
- (optional) pure.raw.py
- ffi
- ffi-requires.txt # lines of paths from which FFI files are required
This Python module creates Python code/bytecode object.
In CPython, every Python file will be compiled to a Python code object, which will finally be executed in CPython virtual machine.
In the earlier design, we create the code object in pure.raw.py,
but don't execute it, for achieving the further flexibility of caching and composition of our compilation.
Unfortunately, due to the heavy code generation by PureScript's type-level computation, the generated pure.raw.py can be always very huge and cause a MemoryError when you want to import it as a python module.
To address this, we come up with a data file format topdown and use it to generate pure.zip.py, which is actually a zip file and shall be regarded as a compressed version of pure.raw.py, but also parse faster than a regular Python module. Sometimes, pure.raw.py can be more than 300MB,
which certainly crash any python executable, but equivalent pure.zip.py can be only 50KB, with orders-of-magnitude speed up on parsing.
This is, actually the loader for corresponding pure.zip.py/pure.raw.py.
This module implements the concrete code caching system which avoids the redundant Python source code to bytecode compilation, and finally greatly reduce the module loading time.
Hence, a PureScript module A.B compiled by PureScript-Python
will be able to imported by the statement import output_top_dir.A.B.pure.
The code of pure.py, corresponding to a PureScript module, is fixed to be
from purescripto import LoadPureScript
__py__ = globals()
__ps__ = LoadPureScript(__file__, __name__)
__all__ = list(__ps__)
__py__.update(__ps__)which relies on the Python package purescripto.
The Python package purescripto provides a common RTS and supplements all required functionalities for being a full featured PureScript backend.