Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specification Tagging #3113

Merged
merged 11 commits into from
Mar 27, 2024
Merged

Specification Tagging #3113

merged 11 commits into from
Mar 27, 2024

Conversation

OAGr
Copy link
Contributor

@OAGr OAGr commented Mar 20, 2024

Simple functionality to allow for Specifications, with a new specification tag.

This is very experimental for now - we won't document for public users yet, but this seems good for us to start using.

image

I didn't add tests in squiggle-language because there's not much real functionality there. (Specification objects hold a bit of information, but don't really do hing novel)

I'd note that we might not want "title" and "description" to be part of this object - but instead, to be added by Tags.

Copy link

changeset-bot bot commented Mar 20, 2024

🦋 Changeset detected

Latest commit: 74c4162

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 7 packages
Name Type
@quri/squiggle-lang Patch
@quri/squiggle-components Patch
@quri/ui Patch
@quri/prettier-plugin-squiggle Patch
@quri/versioned-squiggle-components Patch
vscode-squiggle Patch
@quri/squiggle-textmate-grammar Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@OAGr OAGr changed the title Specifications Specification Tagging Mar 20, 2024
Copy link

vercel bot commented Mar 20, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
quri-hub ✅ Ready (Inspect) Visit Preview Mar 26, 2024 11:39pm
squiggle-components ✅ Ready (Inspect) Visit Preview Mar 26, 2024 11:39pm
squiggle-website ✅ Ready (Inspect) Visit Preview Mar 26, 2024 11:39pm
1 Ignored Deployment
Name Status Preview Updated (UTC)
quri-ui ⬜️ Ignored (Inspect) Visit Preview Mar 26, 2024 11:39pm

spec = Specification.make(
{
title: "Stock market over time",
description: "The S&P500 stock market price, over time.",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move title and description to tags? Same as with Plot.*, which had title: initially and now they don't.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine moving description to tags. I'm nervous about title, because that should probably be mandatory. Seems weird to have a mandatory tag.

],
frSpecification,
([{ title, description, validate, showAs }]) =>
vSpecification({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(minor)

frSpecification defines pack, so could this be a plain {...} object instead of vSpecification({...}.value?

}),
};
},
{ isDecorator: true }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know why this doesn't work as a decorator?

I couldn't figure it out yet but it fails frSpecification check: playground

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet. It seemed to be something internal, maybe because it's a function or something.

return {
value,
tags: tags.merge({
specification: vSpecification(spec),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe hard-fail if the value already has a spec, since we don't support multiple specs per value yet?

More explicit, and it's always possible to erase the previous spec with Tag.omit(...).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I've just realized that tags semantics might make some things awkward.

Whenever you modify a value, you lose all tags on it. So if you want to tune someone's forecast, you'll need to reattach some relevant tags, but not all of them:

@specification(originalForecast -> Tag.getSpecification)
... // any other relevant tags that you need, but usually not `@name` or `@doc`
// maybe `@format` and `@showAs` and `@startOpen`
myForecast = originalForecast -> truncateLeft(2025)

It's almost like tags should have meta-level flags that would guide whether the tag should usually be copied or erased...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we'll solve this with meta-level tag-copying functions when some common patterns emerge:
originalForecast -> truncateLeft(2025) -> Tag.copyCommonTagsFrom(originalForecast).

value,
tags: tags.merge({
specification: vSpecification(spec),
name: vString(spec.title),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this. Sometimes you might want to export multiple forecasts on the same spec, or import multiple forecasts from different people.

I know you can override it with @name, but you'd want @name("my forecast " + Tag.getName(spec)), which is repetitive.

Maybe we could keep the var name and show spec name next to spec widget? So instead of this:
Screenshot 2024-03-26 at 13 09 16

It'd look like this:
Screenshot 2024-03-26 at 13 10 39

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We often don't have much horizontal space - the value can get quite small, especially when nested.

It seems like this is an issue when:

  1. The user doesn't set a different name, with a tag.
  2. The user would prefer to see the variable name, instead of the spec name.

This seems less likely to me than them preferring to see the spec name.

title: "Stock market over time",
description: "The S&P500 stock market price, over time.",
validate: validate,
showAs: {|e| e(Date(2024))},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example (storybook link) makes me think again about how showAs is too powerful/magical/non-transparent. And, more generally, about the tradeoffs between "output looks nice and clean" and "it's easy to figure out what's going on".

When I'm looking at the viewer, it's not clear what's going on; 2024 is hidden in the source code; tagged fn is called "Stock market over time" but the chart itself is not over time but a slice for 2024; x axis not not labeled so it's not even clear that 0-10-20 labels are not time.

I know most of this could be fixed with more careful @doc and Plot calls, but I'm not complaining about this particular example, I'm more concerned about things being interpretable by someone who hasn't read through the model carefully, and who might not even have deep enough understanding of Squiggle to read through the model, or maybe doesn't have time or attention to allocate; most models in the wild won't be carefully coded, and I want Squiggle Viewer to do the right (most clear, most interpretable) thing by default.

Specific idea (out of scope for this PR): when the most powerful version of @showAs is applied, which doesn't just customize axes but applies an arbitrary transformation of the value, indicate that explicitly in the viewer with an icon, and allow users to fall back to the original non-transformed value by clicking that icon.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we just remove showAs for now? It doesn't add too much value ( could always have it be imported manually), and is confusing, as you point out.

isEqual(other: VSpecification) {
return (
this.value.title === other.value.title &&
this.value.description === other.value.description
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense to treat specs similar to JS Symbols, and Spec.make() == Spec.make() should be false.

So I'd suggest a plain identity comparison here, this.value === other.

[frWithTags(frAny({ genericName: "A" })), frSpecification],
frWithTags(frAny({ genericName: "A" })),
([{ value, tags }, spec], reducer) => {
const showAs = spec.showAs && reducer.call(spec.showAs, [value]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary?

Possibly I'm missing something, but couldn't you copy spec.showAs to the value tag, instead of calling it here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried this and it didn't work in your example, because the original @showAs is more strict in its current signature than the version in your example.

But then it seems surprising/inconsistent to relax that limitation in this specific situtation, because the limitation was intentional? If we want to allow a generic @showAs(any) => any then we should allow it everywhere.

(see also: my another comment on how @showAs is too powerful)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants