-
Notifications
You must be signed in to change notification settings - Fork 0
Implementation Plans
What is known to be broken, and what is coming. Nothing here carries a date. Items move off this page when they ship, and the pages that describe current behaviour are updated at the same time.
Two rules constrain everything below, and any item that would violate them needs a design answer first:
- The compiled
.stanfile stays readable, committable, and runnable without Laplace. - Laplace does not parse Stan's semantics. Anything that requires understanding your model, rather than your imports, is a bigger change than it looks.
Today. laplace doc pkg::func prints only the first signature it finds. A user looking up an overloaded function sees one form and has no way to learn the others exist. laplace-survival and laplace-ts are heavily overloaded, so this affects real libraries now.
Fix. Documentation lookup returns every signature with that name, and prints them together, each with its own parameters and doc block. Library authors should not have to list overloads by hand in a README to work around it.
Today. init scans only .stan files, while build and install read both .stan and .laplacelib. A library written in the library dialect therefore produces an empty exports list, and the message says no @laplace-documented functions were found, which points at the doc comments rather than at the real cause. The workaround has been to rename files to .stan, run init, and rename them back.
Fix. init uses the same source-reading path as build and install, so the rename loop disappears. The empty case also distinguishes "no source files found here" from "files found, but none documented", since those need different actions from the author.
Today. init writes one entry per signature, so four overloads of one name produce four identical entries and an inflated count in its output.
This is cosmetic: membership checks ignore duplicates and renaming is idempotent, so existing manifests do not need cleaning up.
Fix. Deduplicate before writing the manifest, and report distinct function names in the summary.
Today. init guesses name from the directory name without sanitizing it, so running it in my-library/ produces name = "my-library", which is not a valid Stan identifier once mangled to my-library__func.
Fix. Sanitize the guess, and reject invalid names in the manifest with a clear message rather than letting them fail later during a build.
Today. import pkg@0.1.0 is parsed and validated as syntax, then ignored. Which version is compiled in comes entirely from laplace.lock, so a model can declare one version in its source and build against another without any warning.
Fix, pending a decision. Either the build errors when the pin and the lock disagree, or the syntax is removed. Erroring is more consistent with the rest of the tool, where every detectable mismatch is a loud failure.
Today. laplace_model() invokes laplace build <path> --out <dir>, but the CLI accepts -o/--output with a file path, not a directory. It also doesn't change into the project directory before building, and laplace build reads laplace.lock from the working directory. Separately, laplace_install_git() refuses to run without an existing laplace.toml, though laplace add itself works without one, and the package DESCRIPTION is still a template with no cmdstanr dependency declared.
Fix. Correct the flag and the output path, set the working directory to the model's project for the duration of the call, drop the manifest precondition, and write a real DESCRIPTION.
Now. Looking a function up means leaving your editor for a terminal and running laplace doc pkg::func.
Planned. The language server reads the same docs.json sidecar and surfaces it in the editor: hover over a namespaced call to see the signature, brief, parameters and example, with a panel for the full documentation of a function or a whole package. Nothing about the data changes, only where it is displayed. This pairs directly with the overload fix above, since a hover that shows one of four signatures has the same problem the CLI does.
Planned. textDocument/signatureHelp, a standard LSP request separate from completion. As you type gaussian_process::rbf_cov(, the editor shows rbf_cov(x, alpha, rho) with the current parameter highlighted, and each @param description alongside it.
This is where Laplace's existing signature and doc extraction pays off twice: the same parsed data drives the CLI, hover, and signature help.
Planned. Stan has no named arguments. Laplace can offer them because it resolves them away at compile time: look up the signature, map each name to its position, and emit a plain positional call.
// what you write
gaussian_process::rbf_cov(x = x, alpha = 1.0, rho = 0.5)
// what Stan gets
gaussian_process__rbf_cov(x, 1.0, 0.5)The output remains ordinary Stan that anyone can read, which is the test every feature here has to pass.
Points to settle during design:
- Overloads. A name maps to a position only once the overload is chosen, so resolution has to pick the signature whose parameter names match, and report clearly when several or none do.
-
Your own functions. Named arguments should work for functions you define in your own
functions { }block, not only for library calls. Signatures are already scanned, so the information is there. - Partial use. Whether positional and named arguments can be mixed in one call, and if so, whether names must come last.
- Errors. An unknown parameter name must fail at build time with the function's real parameter list, not produce a misordered call.
Planned. The parser already reads UTF-8, so mathematical identifiers can be allowed directly: α, σ², x̂. Some symbols would also be parsed as real operators, among them ∈, ≤, ⊆, √ and ∘.
The appeal is obvious for a language whose users write the mathematics down before they write the model.
This is the item furthest from Laplace's current design, and the one with most to decide, because Stan identifiers are ASCII and the generated file has to stay valid Stan:
-
Identifier mapping.
αhas to become something in the output. The mapping must be readable (alpha, not a hash), stable across versions, since it ends up in committed.stanfiles, and collision-safe when a model uses bothαandalpha. -
Operator lowering. Each operator needs an exact Stan equivalent;
∈and⊆in particular have no single obvious translation and may be better left out of a first version than guessed at. -
Byte-for-byte passthrough. Today Laplace rewrites only
pkg::func(call sites and copies everything else verbatim. Unicode identifiers mean rewriting identifiers inside blocks Laplace deliberately does not parse. That is the real cost of this feature, and it needs a narrow, well-tested mechanism rather than a general one. -
Error mapping.
stancerrors report positions in the generated file. Laplace already maps output positions back to source for--validate; renaming identifiers must keep that mapping honest.
A plausible first version is Unicode identifiers only, with operators deferred until the identifier mapping has proven itself.
Not committed, and listed so they are not lost.
-
Author and citation metadata in
laplace.toml. Fields such asauthorsanddoi, printed bylaplace docand shown on Ecosystem, so credit travels with the function rather than living only in a README. - Re-exports. Today a package's imports are strictly private and there is no re-export mechanism. A curated "meta-package" that bundles several libraries would need one.
-
A
laplace checkfor library authors that runs the export, documentation and naming checks from Writing a Library's checklist in one command.
Issues and suggestions go to the [laplace repository](https://github.com/mlatinov/laplace). A report is most useful with the .laplace source, the command you ran, and what you expected instead.