Try it — a miniature Flash Fill. Give a couple of examples of the transformation you want (an input and the output you'd like), then hit Synthesize. A tiny search engine hunts through a small library of string operations for a program that matches all your examples.
<p class="hint">Give a couple of examples of the transformation you want, then Synthesize. The engine searches a small library of string operations for a program matching <b>all</b> examples and applies it to the test input.</p>
<table class="ex"><thead><tr><th>input</th><th>→</th><th>wanted output</th></tr></thead><tbody id="rows"></tbody></table>
<div class="testrow">test input: <input id="test" type="text" value="Grace Hopper" /></div>
<button id="go" type="button">Synthesize</button>
<div id="out" class="out"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .8rem; line-height: 1.45; }
.ex { border-collapse: collapse; width: 100%; max-width: 440px; margin-bottom: .7rem; }
.ex th { font: 600 12px system-ui; color: #777; text-align: left; padding: .2rem .3rem; }
.ex td { padding: .15rem .3rem; }
.ex td.arrow { color: #aaa; text-align: center; }
.ex input { font: 600 14px ui-monospace, monospace; padding: .35rem .5rem; border: 1px solid #cdd9e2; border-radius: 6px; width: 100%; }
.testrow { font: 600 14px system-ui; color: #1d3557; margin-bottom: .7rem; display: flex; align-items: center; gap: .5rem; }
.testrow input { font: 700 14px ui-monospace, monospace; padding: .35rem .5rem; border: 1px solid #cdd9e2; border-radius: 6px; }
button { font: 600 14px system-ui, sans-serif; padding: .5rem 1.1rem; border: 1px solid #457b9d; background: #457b9d; color: #fff; border-radius: 8px; cursor: pointer; }
.out { margin-top: .8rem; font: 600 14px system-ui; line-height: 1.6; min-height: 3em; }
.out .prog { font-family: ui-monospace, monospace; background: #1d2733; color: #e6edf3; padding: .5rem .7rem; border-radius: 8px; display: block; margin: .4rem 0; font-size: 12.5px; }
.out .pred { font-size: 1.05rem; }
.out .pred b { color: #0a7d33; font-family: ui-monospace, monospace; }
.out .none { color: #c0392b; font-weight: 700; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Program synthesis by enumeration over a tiny string-transform DSL (Flash Fill style). The engine returns the first program in its library consistent with ALL examples — preferring simpler ones — then applies it to a new input.
function toks(s) { return (s || '').trim().split(/\s+/).filter(Boolean); }
const cap = w => w ? w[0].toUpperCase() + w.slice(1) : '';
const LIB = [
{ name: 'last + ", " + first[0] + "."', f: s => { const t = toks(s); return t.length < 2 ? '' : t[t.length - 1] + ', ' + t[0][0].toUpperCase() + '.'; } },
{ name: 'first[0] + ". " + last', f: s => { const t = toks(s); return t.length < 2 ? '' : t[0][0].toUpperCase() + '. ' + t[t.length - 1]; } },
{ name: 'first + " " + last (unchanged)', f: s => toks(s).join(' ') },
{ name: 'last + " " + first', f: s => { const t = toks(s); return t.length < 2 ? '' : t[t.length - 1] + ' ' + t[0]; } },
{ name: 'first[0] + last[0] (initials)', f: s => { const t = toks(s); return t.length < 2 ? '' : (t[0][0] + t[t.length - 1][0]).toUpperCase(); } },
{ name: 'UPPERCASE the whole thing', f: s => (s || '').toUpperCase() },
{ name: 'lowercase the whole thing', f: s => (s || '').toLowerCase() },
{ name: 'first name only', f: s => toks(s)[0] || '' },
{ name: 'last name only', f: s => { const t = toks(s); return t[t.length - 1] || ''; } },
{ name: 'last (UPPER) + ", " + first', f: s => { const t = toks(s); return t.length < 2 ? '' : t[t.length - 1].toUpperCase() + ', ' + cap(t[0]); } }
];
function rows() {
return [...document.querySelectorAll('#rows tr')].map(tr => ({
in: tr.querySelector('.in').value, out: tr.querySelector('.out-cell').value
})).filter(r => r.in.trim() && r.out.trim());
}
function synth() {
const ex = rows(); const out = document.getElementById('out');
if (ex.length < 1) { out.innerHTML = '<span class="none">Give at least one input → output example.</span>'; return; }
const prog = LIB.find(p => ex.every(e => p.f(e.in) === e.out));
if (!prog) { out.innerHTML = '<span class="none">No program in my little library matches all those examples.</span> Try a transformation it knows (initials, reorder, case…), or add an example.'; return; }
const test = document.getElementById('test').value;
out.innerHTML = fmt('Synthesized program:<span class="prog">output = %name%</span><span class="pred">On <code>%test%</code> → <b>%v%</b></span>', { name: prog.name, test: test, v: prog.f(test) || '—' });
}
function init() {
const seed = [['Ada Lovelace', 'Lovelace, A.'], ['Alan Turing', 'Turing, A.'], ['', '']];
document.getElementById('rows').innerHTML = seed.map(([i, o]) =>
fmt('<tr><td><input class="in" type="text" value="%i%" placeholder="e.g. Jane Doe"/></td><td class="arrow">→</td><td><input class="out-cell" type="text" value="%o%" placeholder="e.g. Doe, J."/></td></tr>', { i: i, o: o })).join('');
document.getElementById('go').addEventListener('click', synth);
synth();
}
init();
<p class="hint">Give a couple of examples of the transformation you want, then Synthesize. The engine searches a small library of string operations for a program matching <b>all</b> examples and applies it to the test input.</p>
<table class="ex"><thead><tr><th>input</th><th>→</th><th>wanted output</th></tr></thead><tbody id="rows"></tbody></table>
<div class="testrow">test input: <input id="test" type="text" value="Grace Hopper" /></div>
<button id="go" type="button">Synthesize</button>
<div id="out" class="out"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .8rem; line-height: 1.45; }
.ex { border-collapse: collapse; width: 100%; max-width: 440px; margin-bottom: .7rem; }
.ex th { font: 600 12px system-ui; color: #777; text-align: left; padding: .2rem .3rem; }
.ex td { padding: .15rem .3rem; }
.ex td.arrow { color: #aaa; text-align: center; }
.ex input { font: 600 14px ui-monospace, monospace; padding: .35rem .5rem; border: 1px solid #cdd9e2; border-radius: 6px; width: 100%; }
.testrow { font: 600 14px system-ui; color: #1d3557; margin-bottom: .7rem; display: flex; align-items: center; gap: .5rem; }
.testrow input { font: 700 14px ui-monospace, monospace; padding: .35rem .5rem; border: 1px solid #cdd9e2; border-radius: 6px; }
button { font: 600 14px system-ui, sans-serif; padding: .5rem 1.1rem; border: 1px solid #457b9d; background: #457b9d; color: #fff; border-radius: 8px; cursor: pointer; }
.out { margin-top: .8rem; font: 600 14px system-ui; line-height: 1.6; min-height: 3em; }
.out .prog { font-family: ui-monospace, monospace; background: #1d2733; color: #e6edf3; padding: .5rem .7rem; border-radius: 8px; display: block; margin: .4rem 0; font-size: 12.5px; }
.out .pred { font-size: 1.05rem; }
.out .pred b { color: #0a7d33; font-family: ui-monospace, monospace; }
.out .none { color: #c0392b; font-weight: 700; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Program synthesis by enumeration over a tiny string-transform DSL (Flash Fill style). The engine returns the first program in its library consistent with ALL examples — preferring simpler ones — then applies it to a new input.
function toks(s) { return (s || '').trim().split(/\s+/).filter(Boolean); }
const cap = w => w ? w[0].toUpperCase() + w.slice(1) : '';
const LIB = [
{ name: 'last + ", " + first[0] + "."', f: s => { const t = toks(s); return t.length < 2 ? '' : t[t.length - 1] + ', ' + t[0][0].toUpperCase() + '.'; } },
{ name: 'first[0] + ". " + last', f: s => { const t = toks(s); return t.length < 2 ? '' : t[0][0].toUpperCase() + '. ' + t[t.length - 1]; } },
{ name: 'first + " " + last (unchanged)', f: s => toks(s).join(' ') },
{ name: 'last + " " + first', f: s => { const t = toks(s); return t.length < 2 ? '' : t[t.length - 1] + ' ' + t[0]; } },
{ name: 'first[0] + last[0] (initials)', f: s => { const t = toks(s); return t.length < 2 ? '' : (t[0][0] + t[t.length - 1][0]).toUpperCase(); } },
{ name: 'UPPERCASE the whole thing', f: s => (s || '').toUpperCase() },
{ name: 'lowercase the whole thing', f: s => (s || '').toLowerCase() },
{ name: 'first name only', f: s => toks(s)[0] || '' },
{ name: 'last name only', f: s => { const t = toks(s); return t[t.length - 1] || ''; } },
{ name: 'last (UPPER) + ", " + first', f: s => { const t = toks(s); return t.length < 2 ? '' : t[t.length - 1].toUpperCase() + ', ' + cap(t[0]); } }
];
function rows() {
return [...document.querySelectorAll('#rows tr')].map(tr => ({
in: tr.querySelector('.in').value, out: tr.querySelector('.out-cell').value
})).filter(r => r.in.trim() && r.out.trim());
}
function synth() {
const ex = rows(); const out = document.getElementById('out');
if (ex.length < 1) { out.innerHTML = '<span class="none">Give at least one input → output example.</span>'; return; }
const prog = LIB.find(p => ex.every(e => p.f(e.in) === e.out));
if (!prog) { out.innerHTML = '<span class="none">No program in my little library matches all those examples.</span> Try a transformation it knows (initials, reorder, case…), or add an example.'; return; }
const test = document.getElementById('test').value;
out.innerHTML = fmt('Synthesized program:<span class="prog">output = %name%</span><span class="pred">On <code>%test%</code> → <b>%v%</b></span>', { name: prog.name, test: test, v: prog.f(test) || '—' });
}
function init() {
const seed = [['Ada Lovelace', 'Lovelace, A.'], ['Alan Turing', 'Turing, A.'], ['', '']];
document.getElementById('rows').innerHTML = seed.map(([i, o]) =>
fmt('<tr><td><input class="in" type="text" value="%i%" placeholder="e.g. Jane Doe"/></td><td class="arrow">→</td><td><input class="out-cell" type="text" value="%o%" placeholder="e.g. Doe, J."/></td></tr>', { i: i, o: o })).join('');
document.getElementById('go').addEventListener('click', synth);
synth();
}
init();
When it finds one, it shows the program it discovered and applies it to a fresh input. Change the examples and watch the synthesized program change too. With just two examples it usually guesses right — but notice: more examples pin it down better, because a few cases never fully specify what you mean.
Comments
Loading comments...