{"action":"created","comment":{"url":"https://api.github.com/repos/apple/swift-evolution/pulls/comments/48002433","id":48002433,"diff_hunk":"@@ -0,0 +1,207 @@\n+# Either\n+\n+* Proposal: [SE-0015](https://github.com/apple/swift-evolution/blob/master/proposals/0015-either.md)\n+* Author(s): [TypeLift](https://github.com/TypeLift)\n+* Status: **Review**\n+* Review manager: TBD\n+\n+## Introduction\n+\n+This proposal details the addition of a left-biased sum type to the\n+Swift Standard Library.  Earlier attempts at adding this have been too\n+specifically focused on error handling (duplicating functionality\n+`throws` already provides), whereas this implementation will focus on\n+data, organization, and type safety.  We believe that adding the type\n+to the standard library and simultaneously emphasizing its use cases \n+-that is, when you need a type that represents exactly 2 disjoint possibilities-\n+can dispel the confusion caused in other languages\n+and quell the conflict with `throws`.\n+\n+## Motivation\n+\n+Inevitably, it seems languages reach the point where they see the need\n+to handle finite-argument disjoint variants with a data type as was\n+done in C++, C#, D, F#, SML, Haskell, Scala, ALGOL, and many others.\n+When coupled with a strong, static type system they can be made even\n+more useful because support for totality checking and safety come from\n+the language itself.  Recently, certain prominent implementations have\n+chosen to use an `Either` type to represent control flows that can\n+possibly raise errors.  But Either can be written without this\n+convention to simply be a generic type, which is what we propose.\n+\n+As before, unlike `throws`, a disjoint union type can be applied in arbitrary\n+positions, used as a member, and easily checked for completeness\n+at compile time.  In addition, the lack of a standard union type has\n+led the Swift community to create [numerous](https://github.com/search?utf8=✓&q=Either+language%3Aswift) duplicate implementations of the \n+same mutually incompatible types over and over and over again.  In the \n+interest of promoting a type that there has received clear interest by the \n+community, the addition to the Standard Library is necessary.\n+\n+## Proposed solution\n+\n+The Swift Standard Library will be updated to include a left-biased\n+sum type we have called `Either` - though other names may be\n+appropriate depending on how the type is implemented.\n+\n+## Detailed design\n+\n+A complete implementation, based on the [Swiftx](https://github.com/typelift/Swiftx/blob/master/Swiftx/Either.swift) library's implementation, with comments is given below:\n+\n+```swift\n+/// The `Either` type represents values with two possibilities:\n+/// `.Left(LeftValue)` or `.Right(RightValue)`.\n+///\n+/// The `Either` type is left-biased by convention.  That is, the values in the\n+/// `Left` half of the `Either` are considered fair game to be transformed using\n+/// e.g. `map` and `flatMap` while values in the `Right` half of the `Either`\n+/// are considered constant.\n+public enum Either<LeftValue, RightValue> {\n+\tcase Left(LeftValue)\n+\tcase Right(RightValue)\n+\n+\t/// Much like the ?? operator for `Optional` types, takes a value and a\n+\t/// function, and if the receiver is `.Right`, returns the value, otherwise\n+\t/// maps the function over the value in `.Left` and returns that value.\n+\tpublic func fold<U>(value : U, @noescape f : (LeftValue) throws -> U) rethrows -> U {\n+\t\treturn try self.either(onLeft: f, onRight: { _ in value });\n+\t}\n+\n+\t/// Applies the given function to any left values contained in the receiver,\n+\t/// leaving any right values untouched.\n+\tpublic func map<U>(@noescape f: (LeftValue) throws -> U) rethrows -> Either<U, RightValue> {\n+\t\tswitch self {\n+\t\tcase let .Left(l):\n+\t\t\treturn .Left(try f(l))\n+\t\tcase let .Right(r):\n+\t\t\treturn .Right(r)\n+\t\t}\n+\t}\n+\n+\t/// If the `Either` is `Right`, simply returns a new `Right` with\n+\t/// the value of the receiver. If `Left`, applies the function `f`\n+\t/// and returns the result.\n+\tpublic func flatMap<U>(@noescape f: (LeftValue) throws -> Either<U, RightValue>) rethrows -> Either<U, RightValue> {\n+\t\tswitch self {\n+\t\tcase let .Left(l):\n+\t\t\treturn try f(l)\n+\t\tcase let .Right(r):\n+\t\t\treturn .Right(r)\n+\t\t}\n+\t}\n+\n+\t/// Case analysis for the `Either` type.\n+\t///\n+\t/// If the value is `.Left(a)`, apply the first function to `a`. If it is\n+\t/// `.Right(b)`, apply the second function to `b`.\n+\tpublic func either<U>(@noescape onLeft onLeft : (LeftValue) throws -> U, @noescape onRight : (RightValue) throws -> U) rethrows -> U {\n+\t\tswitch self {\n+\t\tcase let .Left(e):\n+\t\t\treturn try onLeft(e)\n+\t\tcase let .Right(e):\n+\t\t\treturn try onRight(e)\n+\t\t}\n+\t}\n+\n+\t/// Reverses the order of values of the receiver.\n+\tpublic var flip : Either<RightValue, LeftValue> {\n+\t\tswitch self {\n+\t\tcase let .Left(l):\n+\t\t\treturn .Right(l)\n+\t\tcase let .Right(r):\n+\t\t\treturn .Left(r)\n+\t\t}\n+\t}\n+\n+\t/// Determines if this `Either` value is a `Left`.\n+\tpublic var isLeft : Bool {\n+\t\tswitch self {\n+\t\tcase .Left(_):\n+\t\t\treturn true\n+\t\tcase .Right(_):\n+\t\t\treturn false\n+\t\t}\n+\t}\n+\n+\t/// Determines if this `Either` value is a `Right`.\n+\tpublic var isRight : Bool {\n+\t\tswitch self {\n+\t\tcase .Right(_):\n+\t\t\treturn true\n+\t\tcase .Left(_):\n+\t\t\treturn false\n+\t\t}\n+\t}\n+}\n+\n+extension Either : CustomStringConvertible {\n+\t/// A textual representation of `self`.\n+\tpublic var description : String {\n+\t\tswitch self {\n+\t\tcase let .Left(l):\n+\t\t\treturn \"Left(\\(l))\"\n+\t\tcase let .Right(r):\n+\t\t\treturn \"Right(\\(r))\"\n+\t\t}\n+\t}\n+}\n+\n+public func == <LeftValue : Equatable, RightValue : Equatable>(lhs : Either<LeftValue, RightValue>, rhs : Either<LeftValue, RightValue>) -> Bool {\n+\tswitch (lhs, rhs) {\n+\tcase let (.Left(l), .Left(r)) where l == r:\n+\t\treturn true\n+\tcase let (.Right(l), .Right(r)) where l == r:\n+\t\treturn true\n+\tdefault:\n+\t\treturn false\n+\t}\n+}\n+\n+public func != <LeftValue : Equatable, RightValue : Equatable>(lhs : Either<LeftValue, RightValue>, rhs : Either<LeftValue, RightValue>) -> Bool {\n+\treturn !(lhs == rhs)\n+}\n+```\n+\n+## Impact on existing code\n+\n+As this is an addition to the Standard Library, no existing code should be affected\n+unless the author happens to be using the identifier Either - in which case\n+there is a strong chance that their Either and our Either are the same\n+thing, aligning with the goal of removing duplicate implementations of\n+this common type.\n+\n+The fears of the previous proposal that attempted to put a `Result<T>`\n+type in the Standard Library, of duplicating existing functionality with respect to\n+`throws` remain, but as noted before `throws` is not as\n+flexible or declarative enough for all possible cases.  If necessary,\n+a note can be left in the documentation warning away users of the\n+`Either` type that really need `throws`.","path":"proposals/0015-either.md","position":177,"original_position":177,"commit_id":"147d8480f7c79e3b5df544c87563ade562a8ea61","original_commit_id":"19ca77f8c2884bc6a114ae4cf1e939119cffcb4a","user":{"login":"pthariensflame","id":1847577,"avatar_url":"https://avatars.githubusercontent.com/u/1847577?v=3","gravatar_id":"","url":"https://api.github.com/users/pthariensflame","html_url":"https://github.com/pthariensflame","followers_url":"https://api.github.com/users/pthariensflame/followers","following_url":"https://api.github.com/users/pthariensflame/following{/other_user}","gists_url":"https://api.github.com/users/pthariensflame/gists{/gist_id}","starred_url":"https://api.github.com/users/pthariensflame/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pthariensflame/subscriptions","organizations_url":"https://api.github.com/users/pthariensflame/orgs","repos_url":"https://api.github.com/users/pthariensflame/repos","events_url":"https://api.github.com/users/pthariensflame/events{/privacy}","received_events_url":"https://api.github.com/users/pthariensflame/received_events","type":"User","site_admin":false},"body":"Further improvement of https://github.com/TypeLift/Focus is effectively blocked on the availability of a universal `Either`, since it's crucial to more powerful prisms, as well as even the mere existence of traversals and partial lenses.","created_at":"2015-12-18T08:07:16Z","updated_at":"2015-12-18T08:07:16Z","html_url":"https://github.com/apple/swift-evolution/pull/67#discussion_r48002433","pull_request_url":"https://api.github.com/repos/apple/swift-evolution/pulls/67","_links":{"self":{"href":"https://api.github.com/repos/apple/swift-evolution/pulls/comments/48002433"},"html":{"href":"https://github.com/apple/swift-evolution/pull/67#discussion_r48002433"},"pull_request":{"href":"https://api.github.com/repos/apple/swift-evolution/pulls/67"}}},"pull_request":{"url":"https://api.github.com/repos/apple/swift-evolution/pulls/67","id":54046092,"html_url":"https://github.com/apple/swift-evolution/pull/67","diff_url":"https://github.com/apple/swift-evolution/pull/67.diff","patch_url":"https://github.com/apple/swift-evolution/pull/67.patch","issue_url":"https://api.github.com/repos/apple/swift-evolution/issues/67","number":67,"state":"open","locked":false,"title":"Either","user":{"login":"CodaFi","id":1896383,"avatar_url":"https://avatars.githubusercontent.com/u/1896383?v=3","gravatar_id":"","url":"https://api.github.com/users/CodaFi","html_url":"https://github.com/CodaFi","followers_url":"https://api.github.com/users/CodaFi/followers","following_url":"https://api.github.com/users/CodaFi/following{/other_user}","gists_url":"https://api.github.com/users/CodaFi/gists{/gist_id}","starred_url":"https://api.github.com/users/CodaFi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CodaFi/subscriptions","organizations_url":"https://api.github.com/users/CodaFi/orgs","repos_url":"https://api.github.com/users/CodaFi/repos","events_url":"https://api.github.com/users/CodaFi/events{/privacy}","received_events_url":"https://api.github.com/users/CodaFi/received_events","type":"User","site_admin":false},"body":"This proposal implements a left-biased sum type for the Swift Standard Library.\r\n\r\nPrevious mailing list discussions can be found [hereabouts](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001394.html).","created_at":"2015-12-17T23:23:10Z","updated_at":"2015-12-18T08:07:16Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5c856e47594f2bc3ddbca6b84816328239026588","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/apple/swift-evolution/pulls/67/commits","review_comments_url":"https://api.github.com/repos/apple/swift-evolution/pulls/67/comments","review_comment_url":"https://api.github.com/repos/apple/swift-evolution/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apple/swift-evolution/issues/67/comments","statuses_url":"https://api.github.com/repos/apple/swift-evolution/statuses/147d8480f7c79e3b5df544c87563ade562a8ea61","head":{"label":"typelift:either-or","ref":"either-or","sha":"147d8480f7c79e3b5df544c87563ade562a8ea61","user":{"login":"typelift","id":8847821,"avatar_url":"https://avatars.githubusercontent.com/u/8847821?v=3","gravatar_id":"","url":"https://api.github.com/users/typelift","html_url":"https://github.com/typelift","followers_url":"https://api.github.com/users/typelift/followers","following_url":"https://api.github.com/users/typelift/following{/other_user}","gists_url":"https://api.github.com/users/typelift/gists{/gist_id}","starred_url":"https://api.github.com/users/typelift/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/typelift/subscriptions","organizations_url":"https://api.github.com/users/typelift/orgs","repos_url":"https://api.github.com/users/typelift/repos","events_url":"https://api.github.com/users/typelift/events{/privacy}","received_events_url":"https://api.github.com/users/typelift/received_events","type":"Organization","site_admin":false},"repo":{"id":47861894,"name":"swift-evolution","full_name":"typelift/swift-evolution","owner":{"login":"typelift","id":8847821,"avatar_url":"https://avatars.githubusercontent.com/u/8847821?v=3","gravatar_id":"","url":"https://api.github.com/users/typelift","html_url":"https://github.com/typelift","followers_url":"https://api.github.com/users/typelift/followers","following_url":"https://api.github.com/users/typelift/following{/other_user}","gists_url":"https://api.github.com/users/typelift/gists{/gist_id}","starred_url":"https://api.github.com/users/typelift/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/typelift/subscriptions","organizations_url":"https://api.github.com/users/typelift/orgs","repos_url":"https://api.github.com/users/typelift/repos","events_url":"https://api.github.com/users/typelift/events{/privacy}","received_events_url":"https://api.github.com/users/typelift/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/typelift/swift-evolution","description":"This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.","fork":true,"url":"https://api.github.com/repos/typelift/swift-evolution","forks_url":"https://api.github.com/repos/typelift/swift-evolution/forks","keys_url":"https://api.github.com/repos/typelift/swift-evolution/keys{/key_id}","collaborators_url":"https://api.github.com/repos/typelift/swift-evolution/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/typelift/swift-evolution/teams","hooks_url":"https://api.github.com/repos/typelift/swift-evolution/hooks","issue_events_url":"https://api.github.com/repos/typelift/swift-evolution/issues/events{/number}","events_url":"https://api.github.com/repos/typelift/swift-evolution/events","assignees_url":"https://api.github.com/repos/typelift/swift-evolution/assignees{/user}","branches_url":"https://api.github.com/repos/typelift/swift-evolution/branches{/branch}","tags_url":"https://api.github.com/repos/typelift/swift-evolution/tags","blobs_url":"https://api.github.com/repos/typelift/swift-evolution/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/typelift/swift-evolution/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/typelift/swift-evolution/git/refs{/sha}","trees_url":"https://api.github.com/repos/typelift/swift-evolution/git/trees{/sha}","statuses_url":"https://api.github.com/repos/typelift/swift-evolution/statuses/{sha}","languages_url":"https://api.github.com/repos/typelift/swift-evolution/languages","stargazers_url":"https://api.github.com/repos/typelift/swift-evolution/stargazers","contributors_url":"https://api.github.com/repos/typelift/swift-evolution/contributors","subscribers_url":"https://api.github.com/repos/typelift/swift-evolution/subscribers","subscription_url":"https://api.github.com/repos/typelift/swift-evolution/subscription","commits_url":"https://api.github.com/repos/typelift/swift-evolution/commits{/sha}","git_commits_url":"https://api.github.com/repos/typelift/swift-evolution/git/commits{/sha}","comments_url":"https://api.github.com/repos/typelift/swift-evolution/comments{/number}","issue_comment_url":"https://api.github.com/repos/typelift/swift-evolution/issues/comments{/number}","contents_url":"https://api.github.com/repos/typelift/swift-evolution/contents/{+path}","compare_url":"https://api.github.com/repos/typelift/swift-evolution/compare/{base}...{head}","merges_url":"https://api.github.com/repos/typelift/swift-evolution/merges","archive_url":"https://api.github.com/repos/typelift/swift-evolution/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/typelift/swift-evolution/downloads","issues_url":"https://api.github.com/repos/typelift/swift-evolution/issues{/number}","pulls_url":"https://api.github.com/repos/typelift/swift-evolution/pulls{/number}","milestones_url":"https://api.github.com/repos/typelift/swift-evolution/milestones{/number}","notifications_url":"https://api.github.com/repos/typelift/swift-evolution/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/typelift/swift-evolution/labels{/name}","releases_url":"https://api.github.com/repos/typelift/swift-evolution/releases{/id}","created_at":"2015-12-12T03:04:09Z","updated_at":"2015-12-12T02:17:18Z","pushed_at":"2015-12-18T02:01:22Z","git_url":"git://github.com/typelift/swift-evolution.git","ssh_url":"git@github.com:typelift/swift-evolution.git","clone_url":"https://github.com/typelift/swift-evolution.git","svn_url":"https://github.com/typelift/swift-evolution","homepage":"","size":123,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"apple:master","ref":"master","sha":"61a1ae352bf425c0d1509904dc55045599a49864","user":{"login":"apple","id":10639145,"avatar_url":"https://avatars.githubusercontent.com/u/10639145?v=3","gravatar_id":"","url":"https://api.github.com/users/apple","html_url":"https://github.com/apple","followers_url":"https://api.github.com/users/apple/followers","following_url":"https://api.github.com/users/apple/following{/other_user}","gists_url":"https://api.github.com/users/apple/gists{/gist_id}","starred_url":"https://api.github.com/users/apple/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apple/subscriptions","organizations_url":"https://api.github.com/users/apple/orgs","repos_url":"https://api.github.com/users/apple/repos","events_url":"https://api.github.com/users/apple/events{/privacy}","received_events_url":"https://api.github.com/users/apple/received_events","type":"Organization","site_admin":false},"repo":{"id":45497910,"name":"swift-evolution","full_name":"apple/swift-evolution","owner":{"login":"apple","id":10639145,"avatar_url":"https://avatars.githubusercontent.com/u/10639145?v=3","gravatar_id":"","url":"https://api.github.com/users/apple","html_url":"https://github.com/apple","followers_url":"https://api.github.com/users/apple/followers","following_url":"https://api.github.com/users/apple/following{/other_user}","gists_url":"https://api.github.com/users/apple/gists{/gist_id}","starred_url":"https://api.github.com/users/apple/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apple/subscriptions","organizations_url":"https://api.github.com/users/apple/orgs","repos_url":"https://api.github.com/users/apple/repos","events_url":"https://api.github.com/users/apple/events{/privacy}","received_events_url":"https://api.github.com/users/apple/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apple/swift-evolution","description":"This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.","fork":false,"url":"https://api.github.com/repos/apple/swift-evolution","forks_url":"https://api.github.com/repos/apple/swift-evolution/forks","keys_url":"https://api.github.com/repos/apple/swift-evolution/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apple/swift-evolution/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apple/swift-evolution/teams","hooks_url":"https://api.github.com/repos/apple/swift-evolution/hooks","issue_events_url":"https://api.github.com/repos/apple/swift-evolution/issues/events{/number}","events_url":"https://api.github.com/repos/apple/swift-evolution/events","assignees_url":"https://api.github.com/repos/apple/swift-evolution/assignees{/user}","branches_url":"https://api.github.com/repos/apple/swift-evolution/branches{/branch}","tags_url":"https://api.github.com/repos/apple/swift-evolution/tags","blobs_url":"https://api.github.com/repos/apple/swift-evolution/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apple/swift-evolution/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apple/swift-evolution/git/refs{/sha}","trees_url":"https://api.github.com/repos/apple/swift-evolution/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apple/swift-evolution/statuses/{sha}","languages_url":"https://api.github.com/repos/apple/swift-evolution/languages","stargazers_url":"https://api.github.com/repos/apple/swift-evolution/stargazers","contributors_url":"https://api.github.com/repos/apple/swift-evolution/contributors","subscribers_url":"https://api.github.com/repos/apple/swift-evolution/subscribers","subscription_url":"https://api.github.com/repos/apple/swift-evolution/subscription","commits_url":"https://api.github.com/repos/apple/swift-evolution/commits{/sha}","git_commits_url":"https://api.github.com/repos/apple/swift-evolution/git/commits{/sha}","comments_url":"https://api.github.com/repos/apple/swift-evolution/comments{/number}","issue_comment_url":"https://api.github.com/repos/apple/swift-evolution/issues/comments{/number}","contents_url":"https://api.github.com/repos/apple/swift-evolution/contents/{+path}","compare_url":"https://api.github.com/repos/apple/swift-evolution/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apple/swift-evolution/merges","archive_url":"https://api.github.com/repos/apple/swift-evolution/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apple/swift-evolution/downloads","issues_url":"https://api.github.com/repos/apple/swift-evolution/issues{/number}","pulls_url":"https://api.github.com/repos/apple/swift-evolution/pulls{/number}","milestones_url":"https://api.github.com/repos/apple/swift-evolution/milestones{/number}","notifications_url":"https://api.github.com/repos/apple/swift-evolution/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apple/swift-evolution/labels{/name}","releases_url":"https://api.github.com/repos/apple/swift-evolution/releases{/id}","created_at":"2015-11-03T21:49:37Z","updated_at":"2015-12-18T07:21:00Z","pushed_at":"2015-12-18T07:19:46Z","git_url":"git://github.com/apple/swift-evolution.git","ssh_url":"git@github.com:apple/swift-evolution.git","clone_url":"https://github.com/apple/swift-evolution.git","svn_url":"https://github.com/apple/swift-evolution","homepage":"","size":209,"stargazers_count":2037,"watchers_count":2037,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":211,"mirror_url":null,"open_issues_count":14,"forks":211,"open_issues":14,"watchers":2037,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apple/swift-evolution/pulls/67"},"html":{"href":"https://github.com/apple/swift-evolution/pull/67"},"issue":{"href":"https://api.github.com/repos/apple/swift-evolution/issues/67"},"comments":{"href":"https://api.github.com/repos/apple/swift-evolution/issues/67/comments"},"review_comments":{"href":"https://api.github.com/repos/apple/swift-evolution/pulls/67/comments"},"review_comment":{"href":"https://api.github.com/repos/apple/swift-evolution/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apple/swift-evolution/pulls/67/commits"},"statuses":{"href":"https://api.github.com/repos/apple/swift-evolution/statuses/147d8480f7c79e3b5df544c87563ade562a8ea61"}}}}