{"action":"created","issue":{"url":"https://api.github.com/repos/thoughtbot/Argo/issues/299","labels_url":"https://api.github.com/repos/thoughtbot/Argo/issues/299/labels{/name}","comments_url":"https://api.github.com/repos/thoughtbot/Argo/issues/299/comments","events_url":"https://api.github.com/repos/thoughtbot/Argo/issues/299/events","html_url":"https://github.com/thoughtbot/Argo/issues/299","id":117957868,"number":299,"title":"Changing from Array-based to List-based","user":{"login":"oisdk","id":12214150,"avatar_url":"https://avatars.githubusercontent.com/u/12214150?v=3","gravatar_id":"","url":"https://api.github.com/users/oisdk","html_url":"https://github.com/oisdk","followers_url":"https://api.github.com/users/oisdk/followers","following_url":"https://api.github.com/users/oisdk/following{/other_user}","gists_url":"https://api.github.com/users/oisdk/gists{/gist_id}","starred_url":"https://api.github.com/users/oisdk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oisdk/subscriptions","organizations_url":"https://api.github.com/users/oisdk/orgs","repos_url":"https://api.github.com/users/oisdk/repos","events_url":"https://api.github.com/users/oisdk/events{/privacy}","received_events_url":"https://api.github.com/users/oisdk/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-11-20T03:23:55Z","updated_at":"2015-11-20T03:54:17Z","closed_at":null,"body":"It seems like Swift.Array as the basic datatype for this kind of decoding isn't very well suited to the task: \r\n\r\n* Building arrays in functional ways (i.e. with `reduce`) is slow\r\n* Functional operations (`map`, etc.) copy each intermediate array\r\n* Laziness is difficult (if not impossible)\r\n\r\nHowever, a lazy list type is easy to define:\r\n\r\n```swift\r\nenum List<T> {\r\n  case Cons(T, () -> List<T>)\r\n  case Nil\r\n}\r\n```\r\n\r\nAnd if you define an operator with an `@autoclosure`, it's lazy:\r\n\r\n```swift\r\npublic func >| <T>(lhs: T, @autoclosure(escaping) rhs: () -> List<T>) -> List<T> {\r\n  return .Cons(lhs, rhs)\r\n}\r\n```\r\n\r\nSome of the functions seem to be a lot more naturally suited to this data structure. `sequence`, for instance:\r\n\r\n```swift\r\npublic func sequence<T>(xs: List<Decoded<T>>) -> Decoded<List<T>> {\r\n  return xs.reduceR(pure([])) { elem, accum in (>|) <^> elem <*> accum }\r\n}\r\n```\r\n\r\nAnyway, I've been fiddling around with some of these ideas [on this fork](https://github.com/oisdk/Argo). I have a fuller implementation of a lazy list [here](https://github.com/oisdk/SwiftDataStructures). Does this sound like a direction that might be useful?"},"comment":{"url":"https://api.github.com/repos/thoughtbot/Argo/issues/comments/158272612","html_url":"https://github.com/thoughtbot/Argo/issues/299#issuecomment-158272612","issue_url":"https://api.github.com/repos/thoughtbot/Argo/issues/299","id":158272612,"user":{"login":"gfontenot","id":124499,"avatar_url":"https://avatars.githubusercontent.com/u/124499?v=3","gravatar_id":"","url":"https://api.github.com/users/gfontenot","html_url":"https://github.com/gfontenot","followers_url":"https://api.github.com/users/gfontenot/followers","following_url":"https://api.github.com/users/gfontenot/following{/other_user}","gists_url":"https://api.github.com/users/gfontenot/gists{/gist_id}","starred_url":"https://api.github.com/users/gfontenot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gfontenot/subscriptions","organizations_url":"https://api.github.com/users/gfontenot/orgs","repos_url":"https://api.github.com/users/gfontenot/repos","events_url":"https://api.github.com/users/gfontenot/events{/privacy}","received_events_url":"https://api.github.com/users/gfontenot/received_events","type":"User","site_admin":false},"created_at":"2015-11-20T03:54:17Z","updated_at":"2015-11-20T03:54:17Z","body":"I think this is _super_ interesting. Especially with the performance issues we've been having. I haven't dug too deep here, but some thoughts off the top of my head:\n\n - I think we'd want to make sure this is an implementation detail, not something to be consumed by users. Or, at least, it should be trivial to get an array back.\n - I'd be (minorly) concerned about introducing this as an external dependency. But I'm also not thrilled about shipping an unrelated type that we expose in the public API. Maybe we _start_ internal and then look at a shared dependency if we see the performance improvements that I'd hope for?\n\nWe've had discussions internally a number of times about making at least parts of Argo lazy. This might be a good step in that direction. I'll dig into this more (including your links) as soon as I sit down in front of a computer.\n\n> On Nov 19, 2015, at 19:23, Oisin Kidney <notifications@github.com> wrote:\n> \n> It seems like Swift.Array as the basic datatype for this kind of decoding isn't very well suited to the task:\n> \n> Building arrays in functional ways (i.e. with reduce) is slow\n> Functional operations (map, etc.) copy each intermediate array\n> Laziness is difficult (if not impossible)\n> However, a lazy list type is easy to define:\n> \n> enum List<T> {\n>   case Cons(T, () -> List<T>)\n>   case Nil\n> }\n> And if you define an operator with an @autoclosure, it's lazy:\n> \n> public func >| <T>(lhs: T, @autoclosure(escaping) rhs: () -> List<T>) -> List<T> {\n>   return .Cons(lhs, rhs)\n> }\n> Some of the functions seem to be a lot more naturally suited to this data structure. sequence, for instance:\n> \n> public func sequence<T>(xs: List<Decoded<T>>) -> Decoded<List<T>> {\n>   return xs.reduceR(pure([])) { elem, accum in (>|) <^> elem <*> accum }\n> }\n> Anyway, I've been fiddling around with some of these ideas on this fork. I have a fuller implementation of a lazy list here. Does this sound like a direction that might be useful?\n> \n> —\n> Reply to this email directly or view it on GitHub.\n> \n"}}