ds300 / derivablejs

Functional Reactive State for JavaScript and TypeScript
Apache License 2.0
515 stars 23 forks source link

Composite Lenses #25

Closed ds300 closed 8 years ago

ds300 commented 8 years ago

At the moment 'lensed atoms' may only have one underlying atom. AFAICT there is no conceptual barrier to allowing more than one underlying atom, and only a minor implementation barrier. I propose adding an alternative to the Lens interface:

type CompositeLens<T> = {
  // no-arg getter uses lexical closure to deref and combine atoms
  get: () => T,

  // one-arg setter to tease apart the value being set and push it
  // up to the atoms manually
  // runs in an implicit transaction.
  set: (value: T) => void
}

Instances of which would be passed to a new top-level function compositeLens to create lensed atoms:

const $FirstName = atom('John');
const $LastName = atom('Steinbeck');

const $Name = compositeLens({
  get: () => $FirstName.get() + ' ' + $LastName.get(),
  set: (val) => {
    const [first, last] = val.split(' ');
    $FirstName.set(first);
    $LastName.set(last);
  }
});

$Name.get(); // => 'John Steinbeck'

$Name.set('James Joyce').

$LastName.get(); // => 'Joyce'
liron00 commented 8 years ago

So Atom::derive is to Derivation as Lens is to CompositeLens.

Yep I've had this idea too for a while too. I think of it as the converse of a derivation / a way to call .set on a derivation.

I think your approach here is good.

ds300 commented 8 years ago

So Atom::derive is to Derivation as Lens is to CompositeLens.

Exactly, yes.

I think your approach here is good.

Thanks :) I'm now mulling over whether to make a new 1-arity version of the top-level lens function for this rather than adding compositeLens.