{"action":"created","issue":{"url":"https://api.github.com/repos/zrho/purescript-optic-ui/issues/4","labels_url":"https://api.github.com/repos/zrho/purescript-optic-ui/issues/4/labels{/name}","comments_url":"https://api.github.com/repos/zrho/purescript-optic-ui/issues/4/comments","events_url":"https://api.github.com/repos/zrho/purescript-optic-ui/issues/4/events","html_url":"https://github.com/zrho/purescript-optic-ui/issues/4","id":103861781,"number":4,"title":"Question: different approach to TraversalP, LensP etc.","user":{"login":"paf31","id":630306,"avatar_url":"https://avatars.githubusercontent.com/u/630306?v=3","gravatar_id":"","url":"https://api.github.com/users/paf31","html_url":"https://github.com/paf31","followers_url":"https://api.github.com/users/paf31/followers","following_url":"https://api.github.com/users/paf31/following{/other_user}","gists_url":"https://api.github.com/users/paf31/gists{/gist_id}","starred_url":"https://api.github.com/users/paf31/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paf31/subscriptions","organizations_url":"https://api.github.com/users/paf31/orgs","repos_url":"https://api.github.com/users/paf31/repos","events_url":"https://api.github.com/users/paf31/events{/privacy}","received_events_url":"https://api.github.com/users/paf31/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":10,"created_at":"2015-08-29T16:25:55Z","updated_at":"2015-09-22T18:01:11Z","closed_at":null,"body":"First of all, thank you for writing this library, it is really excellent.\r\n\r\nI was experimenting with `zoomOne` and `zoomAll`, and was trying to come up with a slightly different, more uniform approach. The idea is that if we can express the `UI` type as `s -> f s` for some `Applicative `f`, then you get lifting over all optics \"for free\". I came up with this: \r\n\r\n```purescript\r\nnewtype Markup a = Markup (Array (HTML a))\r\n\r\ninstance functorMarkup :: Functor Markup where ...\r\n\r\ninstance alternativeMarkup :: Alternative Markup where ...\r\n\r\nnewtype UI state = UI (state -> NonEmpty Markup state)\r\n```\r\n\r\nThen the core combinators become trivial:\r\n\r\n```purescript\r\nlens :: forall a b. LensP a b -> UI b -> UI a\r\nlens l (UI ui) = UI (l ui)\r\n\r\ntraverse :: forall a b. TraversalP a b -> UI b -> UI a\r\ntraverse t (UI ui) = UI (t ui)\r\n```\r\n\r\nThe key is the `NonEmpty` applicative functor which captures something like Halogen's `mergeWith` combinator, combining components in parallel, keeping the latest state from each:\r\n\r\n```purescript\r\ndata NonEmpty f state = NonEmpty state (f state)\r\n  \r\ninstance functorNonEmpty :: (Functor f) => Functor (NonEmpty f) where\r\n  map f (NonEmpty state fa) = NonEmpty (f state) (map f fa)\r\n  \r\ninstance applyNonEmpty :: (Alt f) => Apply (NonEmpty f) where\r\n  apply (NonEmpty f fs) (NonEmpty x xs) = NonEmpty (f x) (map ($ x) fs <|> map f xs)\r\n  \r\ninstance applicativeNonEmpty :: (Alternative f) => Applicative (NonEmpty f) where\r\n  pure a = NonEmpty a empty\r\n```\r\n\r\nI think this could generalize nicely in a few ways:\r\n\r\n- We can use other `Applicative`s instead of just `Markup`, including `Aff`, `Producer`, etc.\r\n- We can use `Eff` inside `UI` to support third-party widgets.\r\n\r\nRight now, I think this library has the best story for component composition I've seen in a PureScript library, but it would be really great to be able to handle third-party components and things like AJAX too.\r\n\r\nI know this is a fairly big change, but would you take a PR?\r\n\r\nThanks"},"comment":{"url":"https://api.github.com/repos/zrho/purescript-optic-ui/issues/comments/142366121","html_url":"https://github.com/zrho/purescript-optic-ui/issues/4#issuecomment-142366121","issue_url":"https://api.github.com/repos/zrho/purescript-optic-ui/issues/4","id":142366121,"user":{"login":"FrigoEU","id":4463490,"avatar_url":"https://avatars.githubusercontent.com/u/4463490?v=3","gravatar_id":"","url":"https://api.github.com/users/FrigoEU","html_url":"https://github.com/FrigoEU","followers_url":"https://api.github.com/users/FrigoEU/followers","following_url":"https://api.github.com/users/FrigoEU/following{/other_user}","gists_url":"https://api.github.com/users/FrigoEU/gists{/gist_id}","starred_url":"https://api.github.com/users/FrigoEU/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/FrigoEU/subscriptions","organizations_url":"https://api.github.com/users/FrigoEU/orgs","repos_url":"https://api.github.com/users/FrigoEU/repos","events_url":"https://api.github.com/users/FrigoEU/events{/privacy}","received_events_url":"https://api.github.com/users/FrigoEU/received_events","type":"User","site_admin":false},"created_at":"2015-09-22T18:01:11Z","updated_at":"2015-09-22T18:01:11Z","body":"The profunctor way is amazing! It took me some time to get how it works, but it's amazingly elegant.\r\n\r\nI have some time available and I'd really like to contribute to this library. Looking at paf31's post above, I feel \"integrating with 3rd part components\" is a place where I could get started. From my own experience, integrating with them mostly comes down to adding some hooks that are run when initializing, finalizing, and sometimes updating components. \r\n\r\nDo you see this as the way to go for Optic UI as well? If yes, I'll take a look around at how Halogen and Thermite implement it and take a stab. Something along these lines:\r\n\r\n    initialize :: forall eff. (HTMLElement -> Eff eff Unit) -> Props\r\n    finalize :: forall eff. (HTMLElement -> Eff eff Unit) -> Props\r\n\r\nAJAX also seems interesting, although I don't know immediately how to start implementing that one."}}