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

Fix laws and simplify implementation #25

Open
wants to merge 16 commits into
base: v1
Choose a base branch
from

Conversation

xaviervia
Copy link
Owner

@xaviervia xaviervia commented Jul 28, 2018

.promap was not following Profunctor laws because .map was acting on the component as-if ReactDream was the identity Functor, without any extra insights into the type. This is now fixed, but the consequence is that there are two breaking changes 💥:

  1. .map acts on the result of running the component, so the React element it outputs.
  2. .promap’s second argument acts on the element as well.

Another effect of this is that there now no helper to apply regular higher-order components to the component inside the ReactDream. So we need a new one.

Since it is still an implementation of Functor, it could be called .map2. It’s not a fantastic name, but it’s accurate. It could probably have an alias. Quick alias brainstorm:

  • .hoc
  • .wrap
  • .update

Quick realization: it might be that HoCs need their own Fantasy Land type, since they do form a Category / Arrow.

@xaviervia xaviervia added this to the v1 milestone Jul 28, 2018
@xaviervia xaviervia changed the base branch from master to v1 July 28, 2018 16:04
@xaviervia xaviervia mentioned this pull request Jul 28, 2018
@xaviervia
Copy link
Owner Author

Right. The obvious name for the method is .enhance

@leostera
Copy link

maybe you want to lift the component to another type where map works from Component to Component rather than from Element to Element?

a = ReactDream(props => </div>)
b = HOC(a)
b.map(hoc1).map(hoc2)

@xaviervia
Copy link
Owner Author

xaviervia commented Jul 28, 2018

Right. 🤦‍♂️ 🤦‍♀️ this is Applicative, but on the identity functor implementation of .map

@xaviervia
Copy link
Owner Author

xaviervia commented Aug 15, 2018

API plan update:

import ReactDream, { ReactBox } from 'react-dream'

ReactDream.Stateless(({ title }) => <h1>{title}</h1>)
  .map(element => <div>{element}</div>)
  .contramap(({ language }) => ({
    title: language === 'en' ? 'Hello' : 'Hola'
  }))
  .enhance(
    withState('updateTitle', 'title', 'Hola')
  )
  .name('Header')

ReactDream.Stateful(class extends Component {})
  .map() // not optimal!

ReactDream.Stateful(class extends Component {})
  .toStateless()
  .map() // optimal but verbose

const withChildren = (Parent, Up, Down) =>
  ReactDream.Stateless(({ parent, up, down }) =>
    <Parent.Component {...parent}>
      <Up {...up} />
      <Down {...down} />
    </Parent.Component>
  )

withChildren(
  Header,
  Title,
  Tagline
)
  .contramap()

// will build a Stateful
ReactDream(class extends Component {})

// will build a Stateless
ReactDream(props => <br />)

ReactDream(props => <hr />)
  .asBox()
  .map()

ReactBox(props => <hr />)
  .asDream()
  .map()

// Equivalences
ReactDream(x).enhance(f) == ReactDream(x).asBox().map(f).asDream()
ReactBox(x).map(f).asDream() == ReactDream(x).enhance(f)
ReactBox.of(f).ap(x) == ReactBox(x).map(f)
ReactBox.of(f).ap(ReactDream(x).asBox()) == ReactBox.of(f).apDream(ReactDream(x))

Keys:

  • ReactBox is introduced. ReactBox is an oh-so-slightly sugared Identity Functor. It is there just to be transformed from and to ReactDream, to provide Applicative for React Components.
  • .enhance is just .map of the Identity Functor. In reality, .enhance just jumps to ReactBox, maps, and then comes back.
  • The jump to ReactBox from ReactDream is done with asBox, and the jump back is done with asDream.
  • In the updated React Dream, Applicative laws don’t apply. Even if they did, it is not that useful. Instead, apDream will be added to the ReactBox so that lifted functions can easily be applied to ReactDreams, mimicking the old behavior of Applicative.

@xaviervia
Copy link
Owner Author

I’m not sure about the names .asDream and .asBox. toDream and toBox might be better ones.

@xaviervia
Copy link
Owner Author

xaviervia commented Aug 16, 2018

Change roadmap:

  • Kill current .ap
  • Kill current .of
  • Introduce Stateless and Stateful constructors with proper inspect
  • Introduce .match on Stateless and on Stateful
  • Introduce .toStateless to Stateless and Stateful. In stateful, it just wraps with a function component. .toStateless(displayName: String) takes the parameter that will set a new display name
  • Reimplement .map for the Stateless and Stateful
  • Reimplement .contramap for the Stateless and Stateful
  • Reimplement .promap for the Stateless and Stateful
  • Reimplement .concat for the Stateless and Stateful
  • Reimplement .chain for the Stateless and Stateful
  • Introduce ReactBox
  • Introduce .map to ReactBox
  • Introduce .of and .ap to ReactBox
  • Introduce .toDream to ReactBox
  • Introduce .toBox to ReactDream
  • Introduce .apDream to ReactBox
  • Introduce .enhance to ReactDream

@xaviervia
Copy link
Owner Author

And for the next iteration:

  • Create package for non-algebraic functions
  • Remove non-algebraic functions

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.

2 participants