{"action":"created","issue":{"url":"https://api.github.com/repos/paldepind/flyd/issues/71","labels_url":"https://api.github.com/repos/paldepind/flyd/issues/71/labels{/name}","comments_url":"https://api.github.com/repos/paldepind/flyd/issues/71/comments","events_url":"https://api.github.com/repos/paldepind/flyd/issues/71/events","html_url":"https://github.com/paldepind/flyd/pull/71","id":115116070,"number":71,"title":"Added dependencies to the end of a stream to promote reusable combines","user":{"login":"c-dante","id":6332726,"avatar_url":"https://avatars.githubusercontent.com/u/6332726?v=3","gravatar_id":"","url":"https://api.github.com/users/c-dante","html_url":"https://github.com/c-dante","followers_url":"https://api.github.com/users/c-dante/followers","following_url":"https://api.github.com/users/c-dante/following{/other_user}","gists_url":"https://api.github.com/users/c-dante/gists{/gist_id}","starred_url":"https://api.github.com/users/c-dante/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/c-dante/subscriptions","organizations_url":"https://api.github.com/users/c-dante/orgs","repos_url":"https://api.github.com/users/c-dante/repos","events_url":"https://api.github.com/users/c-dante/events{/privacy}","received_events_url":"https://api.github.com/users/c-dante/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":6,"created_at":"2015-11-04T18:21:42Z","updated_at":"2015-11-10T16:56:48Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/paldepind/flyd/pulls/71","html_url":"https://github.com/paldepind/flyd/pull/71","diff_url":"https://github.com/paldepind/flyd/pull/71.diff","patch_url":"https://github.com/paldepind/flyd/pull/71.patch"},"body":"Currently, in a dependent stream you have to capture the parent stream in a closure:\r\n```\r\nvar a = flyd.stream(0);\r\nvar b = a.map((x) => x * 2);\r\nvar dep = flyd.stream([a, b], (self, changed) => {\r\n  // Required to defined b outside and capture it\r\n  return a() + b();\r\n});\r\n```\r\n\r\nBecause it requires a closure, you have to write your combine functions in a non reusable fashion.\r\n\r\nI'm proposing the following nonbreaking change to address this:\r\n```\r\nvar sumCombine = (self, changed, x, y) => x() + y();\r\n\r\n// ELSEWHERE\r\nvar a = flyd.stream([depA, depB], sumCombine);\r\nvar b = flyd.stream([depC, depD], sumCombine);\r\nvar allTheSums = flyd.stream([a, b], sumCombine);\r\n```\r\n\r\nThis can be taken a step further for better, reusable join functions. However, it requires a breaking change:\r\n```\r\nflyd.stream([a, b, ...], (a, b, ..., self, changed) => {\r\n});\r\n```\r\n\r\nWhich allows reusable joins, nice partial functions, just all good things functional wants:\r\n```\r\n// Assuming functions are curried by default\r\nvar sumStreams = (a, b, c) => a() + b() + c();\r\nvar addFive = sum(flyd.stream(5));\r\n\r\nvar nice = flyd.stream([someDepA, someDepB], addFive);\r\n```\r\n\r\nSuper sexy combines. Full access to `self` and `changed` if needed (but because return maps nicely, it's no worries)"},"comment":{"url":"https://api.github.com/repos/paldepind/flyd/issues/comments/155485535","html_url":"https://github.com/paldepind/flyd/pull/71#issuecomment-155485535","issue_url":"https://api.github.com/repos/paldepind/flyd/issues/71","id":155485535,"user":{"login":"c-dante","id":6332726,"avatar_url":"https://avatars.githubusercontent.com/u/6332726?v=3","gravatar_id":"","url":"https://api.github.com/users/c-dante","html_url":"https://github.com/c-dante","followers_url":"https://api.github.com/users/c-dante/followers","following_url":"https://api.github.com/users/c-dante/following{/other_user}","gists_url":"https://api.github.com/users/c-dante/gists{/gist_id}","starred_url":"https://api.github.com/users/c-dante/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/c-dante/subscriptions","organizations_url":"https://api.github.com/users/c-dante/orgs","repos_url":"https://api.github.com/users/c-dante/repos","events_url":"https://api.github.com/users/c-dante/events{/privacy}","received_events_url":"https://api.github.com/users/c-dante/received_events","type":"User","site_admin":false},"created_at":"2015-11-10T16:56:48Z","updated_at":"2015-11-10T16:56:48Z","body":"@ericgj, the variadic nature of the dependent stream is captured in multiple places as it stands. Having the fixed-arity \"self, changed\" signature captures nothing about the stream combinator, which is why the current implementation looks to the closure to do comparisions, IE:\r\n```\r\n// a and b are streams\r\nflyd.stream([a, b], (self, changed) => {\r\nif (changed.indexOf(a) !== -1) // do something because `a` changed\r\nif (changed.indexOf(b) !== -1) // do something because `b` changed\r\n});\r\n```\r\nThe problem with this signature is that you cannot curry the combinator, or even define it without a closure. My first change addresses the closure aspect in a non-breaking fashion by passing each dependency as the trailing variables. The problem with them being at the end is that you cannot curry this.\r\n\r\nThe array solution you suggest does nothing to address the problems outlined, and does not allow currying. Example:\r\n```\r\nvar weirdArraySum = (aAndB) => aAndB[0] + aAndB[1];\r\nflyd.stream([depA, depB], weirdArraySum);\r\n```\r\nBut that isn't a curried function -- I cannot curry `weirdArraySum` since it forces a tuple to be applied. \r\n\r\nAn alternative version with unnecessary boilerplate:\r\n```\r\nvar sum = (a, b) => a + b;\r\nflyd.stream([depA, depB], (deps, self, changed) => sum.apply(sum, deps));\r\n```"}}