├── .editorconfig ├── .github ├── CODE_OF_CONDUCT.md └── workflows │ └── ci.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── Makefile ├── Overture.playground ├── Contents.o ├── Pages │ ├── Basics.xcplaygroundpage │ │ └── Contents.swift │ ├── UIKit Setters.xcplaygroundpage │ │ └── Contents.swift │ ├── URLRequest Setters - Immutable.xcplaygroundpage │ │ └── Contents.swift │ └── URLRequest Setters - Mutable.xcplaygroundpage │ │ └── Contents.swift └── contents.xcplayground ├── Package.swift ├── README.md ├── Sources └── Overture │ ├── Chain.swift │ ├── Combining.swift │ ├── Compose.swift │ ├── Concat.swift │ ├── Curry.swift │ ├── Flip.swift │ ├── KeyPath.swift │ ├── Optional.swift │ ├── Pipe.swift │ ├── Result.swift │ ├── Sequence.swift │ ├── Setters.swift │ ├── Uncurry.swift │ ├── Update.swift │ ├── With.swift │ ├── ZipOptional.swift │ ├── ZipResult.swift │ ├── ZipSequence.swift │ └── Zurry.swift └── Tests └── OvertureTests ├── ChainTests.swift ├── ComposeTests.swift ├── ConcatTests.swift ├── CurryTests.swift ├── FlipTests.swift ├── KeyPathTests.swift ├── PipeTests.swift ├── SettersTests.swift ├── UncurryTests.swift ├── WithTests.swift └── ZipTests.swift /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | . 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations 133 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - '*' 10 | 11 | jobs: 12 | build: 13 | name: MacOS 14 | runs-on: macOS-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Run tests 18 | run: make test-swift 19 | 20 | ubuntu: 21 | name: Ubuntu 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@v2 25 | - name: Run tests 26 | run: make test-linux 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | .swiftpm 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | # Pods/ 50 | 51 | # Carthage 52 | # 53 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 54 | # Carthage/Checkouts 55 | 56 | Carthage/Build 57 | 58 | # fastlane 59 | # 60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 61 | # screenshots whenever they are needed. 62 | # For more information about the recommended setup visit: 63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 64 | 65 | fastlane/report.xml 66 | fastlane/Preview.html 67 | fastlane/screenshots 68 | fastlane/test_output 69 | 70 | .DS_Store 71 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mbw234@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Point-Free, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | xcodeproj: 2 | PF_DEVELOP=1 swift run xcodegen 3 | 4 | test-linux: 5 | docker run \ 6 | --rm \ 7 | -v "$(PWD):$(PWD)" \ 8 | -w "$(PWD)" \ 9 | swift:5.1 \ 10 | bash -c 'make test-swift' 11 | 12 | test-macos: 13 | set -o pipefail && \ 14 | xcodebuild test \ 15 | -scheme Overture_macOS \ 16 | -destination platform="macOS" \ 17 | | xcpretty 18 | 19 | test-ios: 20 | set -o pipefail && \ 21 | xcodebuild test \ 22 | -scheme Overture_iOS \ 23 | -destination platform="iOS Simulator,name=iPhone 11 Pro Max,OS=13.2.2" \ 24 | | xcpretty 25 | 26 | test-swift: 27 | swift test \ 28 | --enable-test-discovery \ 29 | --parallel 30 | 31 | test-all: test-linux test-macos test-ios test-swift 32 | -------------------------------------------------------------------------------- /Overture.playground/Contents.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-overture/912dce67981da3c228b9244a7af8dbdab91afd41/Overture.playground/Contents.o -------------------------------------------------------------------------------- /Overture.playground/Pages/Basics.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Overture 3 | 4 | func incr(_ x: Int) -> Int { 5 | return x + 1 6 | } 7 | 8 | func square(_ x: Int) -> Int { 9 | return x * x 10 | } 11 | 12 | [1, 2, 3].map(pipe(incr, square, String.init)) 13 | 14 | let stringWithEncoding = flip(curry(String.init(data:encoding:))) 15 | 16 | let utf8String = stringWithEncoding(.utf8) 17 | 18 | let capitalized = flip(String.capitalized) 19 | 20 | ["hello, world", "and good night"] 21 | .map(capitalized(Locale(identifier: "en"))) 22 | 23 | get(\String.count) 24 | 25 | ["hello, world", "and good night"] 26 | .map(get(\.count)) 27 | 28 | pipe(incr, square, String.init, get(\.count)) 29 | 30 | struct User { 31 | var name: String 32 | var age: Int 33 | } 34 | 35 | let setUserName = prop(\User.name) 36 | let capitalizeUserName = setUserName(capitalized(Locale(identifier: "en"))) 37 | 38 | let setUserAge = prop(\User.age) 39 | let celebrateBirthday = setUserAge(incr) 40 | 41 | let blob = User(name: "Blob", age: 42) 42 | 43 | with(blob, concat( 44 | capitalizeUserName, 45 | celebrateBirthday 46 | )) 47 | 48 | let blobJr = with(blob, concat( 49 | mver(\.name) { $0 += ", Jr." }, 50 | mver(\.age) { $0 -= 30 } 51 | )) 52 | 53 | let blobSr = with(blob, concat( 54 | mver(\.name) { $0 += ", Sr." }, 55 | mver(\.age) { $0 += 30 } 56 | )) 57 | 58 | let users = [ 59 | blob, 60 | blobJr, 61 | blobSr 62 | ] 63 | 64 | users.reduce(0, combining(get(\.age), +)) 65 | users.reduce(into: 0, combining(get(\.age), +=)) 66 | 67 | users.sorted(by: their(get(\.age))) 68 | users.sorted(by: their(get(\.age), >)) 69 | -------------------------------------------------------------------------------- /Overture.playground/Pages/UIKit Setters.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Overture 2 | import UIKit 3 | 4 | // Base Styles 5 | 6 | let autolayoutStyle = mut(\UIView.translatesAutoresizingMaskIntoConstraints, false) 7 | 8 | let roundedStyle = concat( 9 | mut(\UIView.clipsToBounds, true), 10 | mut(\.layer.cornerRadius, 6) 11 | ) 12 | 13 | func borderStyle(color: UIColor, width: CGFloat) -> (UIView) -> Void { 14 | return concat( 15 | mut(\UIView.layer.borderColor, color.cgColor), 16 | mut(\.layer.borderWidth, width) 17 | ) 18 | } 19 | 20 | func buttonFont(_ font: UIFont) -> (UIButton) -> Void { 21 | return { $0.titleLabel?.font = font } 22 | } 23 | 24 | func buttonTitle(_ title: String, for state: UIControlState = .normal) -> (UIButton) -> Void { 25 | return { $0.setTitle(title, for: state) } 26 | } 27 | 28 | func buttonTitleColor(_ color: UIColor, for state: UIControlState = .normal) -> (UIButton) -> Void { 29 | return { $0.setTitleColor(color, for: state) } 30 | } 31 | 32 | // App Styles 33 | 34 | let baseButtonStyle: (UIButton) -> Void = concat( 35 | mut(\.contentEdgeInsets, .init(top: 12, left: 16, bottom: 12, right: 16)), 36 | buttonFont(.systemFont(ofSize: 16)) 37 | ) 38 | 39 | let roundButtonStyle = concat( 40 | baseButtonStyle, 41 | roundedStyle 42 | ) 43 | 44 | let filledButtonStyle = concat( 45 | roundButtonStyle, 46 | mut(\.backgroundColor, .black), 47 | mut(\.tintColor, .white) 48 | ) 49 | 50 | let borderButtonStyle = concat( 51 | roundButtonStyle, 52 | borderStyle(color: .black, width: 2), 53 | buttonTitleColor(.black) 54 | ) 55 | 56 | let nextButton = with( 57 | UIButton(), 58 | concat( 59 | filledButtonStyle, 60 | buttonTitle("Next") 61 | ) 62 | ) 63 | 64 | let cancelButton = with( 65 | UIButton(), 66 | concat( 67 | borderButtonStyle, 68 | buttonTitle("Cancel") 69 | ) 70 | ) 71 | -------------------------------------------------------------------------------- /Overture.playground/Pages/URLRequest Setters - Immutable.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Overture 3 | 4 | let guaranteeHeaders = over(\URLRequest.allHTTPHeaderFields) { $0 ?? [:] } 5 | 6 | let setHeader = { name, value in 7 | concat( 8 | guaranteeHeaders, 9 | set(compose(prop(\.allHTTPHeaderFields), map, prop(\.[name])), value) 10 | ) 11 | } 12 | 13 | let postJson = concat( 14 | set(\.httpMethod, "POST"), 15 | setHeader("Content-Type", "application/json; charset=utf-8") 16 | ) 17 | 18 | let gitHubAccept = setHeader("Accept", "application/vnd.github.v3+json") 19 | 20 | let attachAuthorization = { token in setHeader("Authorization", "Token " + token) } 21 | 22 | let request = with( 23 | URLRequest(url: URL(string: "https://www.pointfree.co/hello")!), 24 | concat( 25 | attachAuthorization("deadbeef"), 26 | gitHubAccept, 27 | postJson 28 | ) 29 | ) 30 | -------------------------------------------------------------------------------- /Overture.playground/Pages/URLRequest Setters - Mutable.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Overture 3 | 4 | let guaranteeHeaders = mver(\URLRequest.allHTTPHeaderFields) { $0 = $0 ?? [:] } 5 | 6 | let setHeader = { name, value in 7 | concat(guaranteeHeaders) { $0.allHTTPHeaderFields?[name] = value } 8 | } 9 | 10 | let postJson = concat( 11 | mut(\.httpMethod, "POST"), 12 | setHeader("Content-Type", "application/json; charset=utf-8") 13 | ) 14 | 15 | let gitHubAccept = setHeader("Accept", "application/vnd.github.v3+json") 16 | 17 | let attachAuthorization = { token in setHeader("Authorization", "Token " + token) } 18 | 19 | let request = with( 20 | URLRequest(url: URL(string: "https://www.pointfree.co/hello")!), 21 | concat( 22 | attachAuthorization("deadbeef"), 23 | gitHubAccept, 24 | postJson 25 | ) 26 | ) 27 | -------------------------------------------------------------------------------- /Overture.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "swift-overture", 7 | products: [ 8 | .library( 9 | name: "Overture", 10 | targets: ["Overture"] 11 | ), 12 | ], 13 | targets: [ 14 | .target( 15 | name: "Overture" 16 | ), 17 | .testTarget( 18 | name: "OvertureTests", 19 | dependencies: ["Overture"] 20 | ), 21 | ] 22 | ) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🎼 Overture 2 | 3 | [![CI](https://github.com/pointfreeco/swift-overture/workflows/CI/badge.svg)](https://actions-badge.atrox.dev/pointfreeco/swift-overture/goto) 4 | [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fpointfreeco%2Fswift-overture%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/pointfreeco/swift-overture) 5 | [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fpointfreeco%2Fswift-overture%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/pointfreeco/swift-overture) 6 | 7 | A library for function composition. 8 | 9 | ## Table of Contents 10 | 11 | - [Motivation](#motivation) 12 | - [Examples](#examples) 13 | - [`pipe`](#pipe) 14 | - [`with` and `update`](#with-and-update) 15 | - [`concat`](#concat) 16 | - [`curry`, `flip`, and `zurry`](#curry-flip-and-zurry) 17 | - [`get`](#get) 18 | - [`prop`](#prop) 19 | - [`over` and `set`](#over-and-set) 20 | - [`mprop`, `mver`, and `mut`](#mprop-mver-and-mut) 21 | - [`zip`](#zip-and-zipwith) 22 | - [FAQ](#faq) 23 | - [Installation](#installation) 24 | - [🎶 Prelude](#-prelude) 25 | - [Interested in learning more?](#interested-in-learning-more) 26 | - [License](#license) 27 | 28 | ## Motivation 29 | 30 | We work with functions all the time, but function composition is hiding in plain sight! 31 | 32 | For instance, we work with functions when we use higher-order methods, like `map` on arrays: 33 | 34 | ``` swift 35 | [1, 2, 3].map { $0 + 1 } 36 | // [2, 3, 4] 37 | ``` 38 | 39 | If we wanted to modify this simple closure to square our value after incrementing it, things begin to get messy. 40 | 41 | ``` swift 42 | [1, 2, 3].map { ($0 + 1) * ($0 + 1) } 43 | // [4, 9, 16] 44 | ``` 45 | 46 | Functions allow us to identify and extract reusable code. Let's define a couple functions that make up the behavior above. 47 | 48 | ``` swift 49 | func incr(_ x: Int) -> Int { 50 | return x + 1 51 | } 52 | 53 | func square(_ x: Int) -> Int { 54 | return x * x 55 | } 56 | ``` 57 | 58 | With these functions defined, we can pass them directly to `map`! 59 | 60 | ``` swift 61 | [1, 2, 3] 62 | .map(incr) 63 | .map(square) 64 | // [4, 9, 16] 65 | ``` 66 | 67 | This refactor reads much better, but it's less performant: we're mapping over the array twice and creating an intermediate copy along the way! While we could use `lazy` to fuse these calls together, let's take a more general approach: function composition! 68 | 69 | ``` swift 70 | [1, 2, 3].map(pipe(incr, square)) 71 | // [4, 9, 16] 72 | ``` 73 | 74 | The `pipe` function glues other functions together! It can take more than two arguments and even change the type along the way! 75 | 76 | ``` swift 77 | [1, 2, 3].map(pipe(incr, square, String.init)) 78 | // ["4", "9", "16"] 79 | ``` 80 | 81 | Function composition lets us build new functions from smaller pieces, giving us the ability to extract and reuse logic in other contexts. 82 | 83 | ``` swift 84 | let computeAndStringify = pipe(incr, square, String.init) 85 | 86 | [1, 2, 3].map(computeAndStringify) 87 | // ["4", "9", "16"] 88 | 89 | computeAndStringify(42) 90 | // "1849" 91 | ``` 92 | 93 | The function is the smallest building block of code. Function composition gives us the ability to fit these blocks together and build entire apps out of small, reusable, understandable units. 94 | 95 | ## Examples 96 | 97 | ### `pipe` 98 | 99 | The most basic building block in Overture. It takes existing functions and smooshes them together. That is, given a function `(A) -> B` and a function `(B) -> C`, `pipe` will return a brand new `(A) -> C` function. 100 | 101 | ``` swift 102 | let computeAndStringify = pipe(incr, square, String.init) 103 | 104 | computeAndStringify(42) 105 | // "1849" 106 | 107 | [1, 2, 3].map(computeAndStringify) 108 | // ["4", "9", "16"] 109 | ``` 110 | 111 | ### `with` and `update` 112 | 113 | The `with` and `update` functions are useful for applying functions to values. They play nicely with the `inout` and mutable object worlds, wrapping otherwise imperative configuration statements in an expression. 114 | 115 | ``` swift 116 | class MyViewController: UIViewController { 117 | let label = updateObject(UILabel()) { 118 | $0.font = .systemFont(ofSize: 24) 119 | $0.textColor = .red 120 | } 121 | } 122 | ``` 123 | 124 | And it restores the left-to-right readability we're used to from the method world. 125 | 126 | ``` swift 127 | with(42, pipe(incr, square, String.init)) 128 | // "1849" 129 | ``` 130 | 131 | Using an `inout` parameter. 132 | 133 | ``` swift 134 | update(&user, mut(\.name, "Blob")) 135 | ``` 136 | 137 | ### `concat` 138 | 139 | The `concat` function composes with single types. This includes composition of the following function signatures: 140 | 141 | - `(A) -> A` 142 | - `(inout A) -> Void` 143 | - `(A) -> Void` 144 | 145 | With `concat`, we can build powerful configuration functions from small pieces. 146 | 147 | ``` swift 148 | let roundedStyle: (UIView) -> Void = { 149 | $0.clipsToBounds = true 150 | $0.layer.cornerRadius = 6 151 | } 152 | 153 | let baseButtonStyle: (UIButton) -> Void = { 154 | $0.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) 155 | $0.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium) 156 | } 157 | 158 | let roundedButtonStyle = concat( 159 | baseButtonStyle, 160 | roundedStyle 161 | ) 162 | 163 | let filledButtonStyle = concat(roundedButtonStyle) { 164 | $0.backgroundColor = .black 165 | $0.tintColor = .white 166 | } 167 | 168 | let button = with(UIButton(type: .system), filledButtonStyle) 169 | ``` 170 | 171 | ### `curry`, `flip`, and `zurry` 172 | 173 | These functions make up the [Swiss army knife](https://www.pointfree.co/episodes/ep5-higher-order-functions) of composition. They give us the power to take existing functions and methods that don't compose (_e.g_, those that take zero or multiple arguments) and restore composition. 174 | 175 | For example, let's transform a string initializer that takes multiple arguments into something that can compose with `pipe`. 176 | 177 | ``` swift 178 | String.init(data:encoding:) 179 | // (Data, String.Encoding) -> String? 180 | ``` 181 | 182 | We use `curry` to transform multi-argument functions into functions that take a single input and return new functions to gather more inputs along the way. 183 | 184 | ``` swift 185 | curry(String.init(data:encoding:)) 186 | // (Data) -> (String.Encoding) -> String? 187 | ``` 188 | 189 | And we use `flip` to flip the order of arguments. Multi-argument functions and methods typically take data first and configuration second, but we can generally apply configuration before we have data, and `flip` allows us to do just that. 190 | 191 | ``` swift 192 | flip(curry(String.init(data:encoding:))) 193 | // (String.Encoding) -> (Data) -> String? 194 | ``` 195 | 196 | Now we have a highly-reusable, composable building block that we can use to build pipelines. 197 | 198 | ``` swift 199 | let stringWithEncoding = flip(curry(String.init(data:encoding:))) 200 | // (String.Encoding) -> (Data) -> String? 201 | 202 | let utf8String = stringWithEncoding(.utf8) 203 | // (Data) -> String? 204 | ``` 205 | 206 | Swift also exposes methods as static, unbound functions. These functions are already in curried form. All we need to do is `flip` them to make them more useful! 207 | 208 | ``` swift 209 | String.capitalized 210 | // (String) -> (Locale?) -> String 211 | 212 | let capitalized = flip(String.capitalized) 213 | // (Locale?) -> (String) -> String 214 | 215 | ["hello, world", "and good night"] 216 | .map(capitalized(Locale(identifier: "en"))) 217 | // ["Hello, World", "And Good Night"] 218 | ``` 219 | 220 | And `zurry` restores composition for functions and methods that take zero arguments. 221 | 222 | ``` swift 223 | String.uppercased 224 | // (String) -> () -> String 225 | 226 | flip(String.uppercased) 227 | // () -> (String) -> String 228 | 229 | let uppercased = zurry(flip(String.uppercased)) 230 | // (String) -> String 231 | 232 | ["hello, world", "and good night"] 233 | .map(uppercased) 234 | // ["HELLO, WORLD", "AND GOOD NIGHT"] 235 | ``` 236 | 237 | ### `get` 238 | 239 | The `get` function produces [getter functions](https://www.pointfree.co/episodes/ep8-getters-and-key-paths) from key paths. 240 | 241 | ``` swift 242 | get(\String.count) 243 | // (String) -> Int 244 | 245 | ["hello, world", "and good night"] 246 | .map(get(\.count)) 247 | // [12, 14] 248 | ``` 249 | 250 | We can even compose other functions into `get` by using the `pipe` function. Here we build a function that increments an integer, squares it, turns it into a string, and then gets the string's character count: 251 | 252 | ```swift 253 | pipe(incr, square, String.init, get(\.count)) 254 | // (Int) -> Int 255 | ``` 256 | 257 | ### `prop` 258 | 259 | The `prop` function produces [setter functions](https://www.pointfree.co/episodes/ep7-setters-and-key-paths) from key paths. 260 | 261 | ``` swift 262 | let setUserName = prop(\User.name) 263 | // ((String) -> String) -> (User) -> User 264 | 265 | let capitalizeUserName = setUserName(capitalized(Locale(identifier: "en"))) 266 | // (User) -> User 267 | 268 | let setUserAge = prop(\User.age) 269 | 270 | let celebrateBirthday = setUserAge(incr) 271 | // (User) -> User 272 | 273 | with(User(name: "blob", age: 1), concat( 274 | capitalizeUserName, 275 | celebrateBirthday 276 | )) 277 | // User(name: "Blob", age: 2) 278 | ``` 279 | 280 | ### `over` and `set` 281 | 282 | The `over` and `set` functions produce `(Root) -> Root` transform functions that work on a `Value` in a structure given a key path (or [setter function](https://www.pointfree.co/episodes/ep7-setters-and-key-paths)). 283 | 284 | The `over` function takes a `(Value) -> Value` transform function to modify an existing value. 285 | 286 | ``` swift 287 | let celebrateBirthday = over(\User.age, incr) 288 | // (User) -> User 289 | ``` 290 | 291 | The `set` function replaces an existing value with a brand new one. 292 | 293 | ```swift 294 | with(user, set(\.name, "Blob")) 295 | ``` 296 | 297 | ### `mprop`, `mver`, and `mut` 298 | 299 | The `mprop`, `mver` and `mut` functions are _mutable_ variants of `prop`, `over` and `set`. 300 | 301 | ```swift 302 | let guaranteeHeaders = mver(\URLRequest.allHTTPHeaderFields) { $0 = $0 ?? [:] } 303 | 304 | let setHeader = { name, value in 305 | concat( 306 | guaranteeHeaders, 307 | { $0.allHTTPHeaderFields?[name] = value } 308 | ) 309 | } 310 | 311 | let request = update( 312 | URLRequest(url: url), 313 | mut(\.httpMethod, "POST"), 314 | setHeader("Authorization", "Token " + token), 315 | setHeader("Content-Type", "application/json; charset=utf-8") 316 | ) 317 | ``` 318 | 319 | ### `zip` and `zip(with:)` 320 | 321 | This is a function that Swift ships with! Unfortunately, it's limited to pairs of sequences. Overture defines `zip` to work with up to ten sequences at once, which makes combining several sets of related data a snap. 322 | 323 | ```swift 324 | let ids = [1, 2, 3] 325 | let emails = ["blob@pointfree.co", "blob.jr@pointfree.co", "blob.sr@pointfree.co"] 326 | let names = ["Blob", "Blob Junior", "Blob Senior"] 327 | 328 | zip(ids, emails, names) 329 | // [ 330 | // (1, "blob@pointfree.co", "Blob"), 331 | // (2, "blob.jr@pointfree.co", "Blob Junior"), 332 | // (3, "blob.sr@pointfree.co", "Blob Senior") 333 | // ] 334 | ``` 335 | 336 | It's common to immediately `map` on zipped values. 337 | 338 | ``` swift 339 | struct User { 340 | let id: Int 341 | let email: String 342 | let name: String 343 | } 344 | 345 | zip(ids, emails, names).map(User.init) 346 | // [ 347 | // User(id: 1, email: "blob@pointfree.co", name: "Blob"), 348 | // User(id: 2, email: "blob.jr@pointfree.co", name: "Blob Junior"), 349 | // User(id: 3, email: "blob.sr@pointfree.co", name: "Blob Senior") 350 | // ] 351 | ``` 352 | 353 | Because of this, Overture provides a `zip(with:)` helper, which takes a tranform function up front and is curried, so it can be composed with other functions using `pipe`. 354 | 355 | ``` swift 356 | zip(with: User.init)(ids, emails, names) 357 | ``` 358 | 359 | Overture also extends the notion of `zip` to work with optionals! It's an expressive way of combining multiple optionals together. 360 | 361 | ``` swift 362 | let optionalId: Int? = 1 363 | let optionalEmail: String? = "blob@pointfree.co" 364 | let optionalName: String? = "Blob" 365 | 366 | zip(optionalId, optionalEmail, optionalName) 367 | // Optional<(Int, String, String)>.some((1, "blob@pointfree.co", "Blob")) 368 | ``` 369 | 370 | And `zip(with:)` lets us transform these tuples into other values. 371 | 372 | ``` swift 373 | zip(with: User.init)(optionalId, optionalEmail, optionalName) 374 | // Optional.some(User(id: 1, email: "blob@pointfree.co", name: "Blob")) 375 | ``` 376 | 377 | Using `zip` can be an expressive alternative to `let`-unwrapping! 378 | 379 | ``` swift 380 | let optionalUser = zip(with: User.init)(optionalId, optionalEmail, optionalName) 381 | 382 | // vs. 383 | 384 | let optionalUser: User? 385 | if let id = optionalId, let email = optionalEmail, let name = optionalName { 386 | optionalUser = User(id: id, email: email, name: name) 387 | } else { 388 | optionalUser = nil 389 | } 390 | ``` 391 | 392 | ## FAQ 393 | 394 | - **Should I be worried about polluting the global namespace with free functions?** 395 | 396 | Nope! Swift has several layers of scope to help you here. 397 | 398 | - You can limit exposing highly-specific functions beyond a single file by using `fileprivate` and `private` scope. 399 | - You can define functions as `static` members inside types. 400 | - You can qualify functions with the module's name (_e.g._, `Overture.pipe(f, g)`). You can even autocomplete free functions from the module's name, so discoverability doesn't have to suffer! 401 | 402 | - **Are free functions that common in Swift?** 403 | 404 | It may not seem like it, but free functions are everywhere in Swift, making Overture extremely useful! A few examples: 405 | 406 | - Initializers, like `String.init`. 407 | - Unbound methods, like `String.uppercased`. 408 | - Enum cases with associated values, like `Optional.some`. 409 | - Ad hoc closures we pass to `map`, `filter`, and other higher-order methods. 410 | - Top-level Standard Library functions like `max`, `min`, and `zip`. 411 | 412 | ## Installation 413 | 414 | You can add Overture to an Xcode project by adding it as a package dependency. 415 | 416 | > https://github.com/pointfreeco/swift-overture 417 | 418 | If you want to use Overture in a [SwiftPM](https://swift.org/package-manager/) project, it's as simple as adding it to a `dependencies` clause in your `Package.swift`: 419 | 420 | ``` swift 421 | dependencies: [ 422 | .package(url: "https://github.com/pointfreeco/swift-overture", from: "0.5.0") 423 | ] 424 | ``` 425 | 426 | ## 🎶 Prelude 427 | 428 | This library was created as an alternative to [swift-prelude](https://www.github.com/pointfreeco/swift-prelude), which is an experimental functional programming library that uses infix operators. For example, `pipe` is none other than the arrow composition operator `>>>`, which means the following are equivalent: 429 | 430 | ```swift 431 | xs.map(incr >>> square) 432 | xs.map(pipe(incr, square)) 433 | ``` 434 | 435 | We know that many code bases are not going to be comfortable introducing operators, so we wanted to reduce the barrier to entry for embracing function composition. 436 | 437 | ## Interested in learning more? 438 | 439 | These concepts (and more) are explored thoroughly in [Point-Free](https://www.pointfree.co), a video series exploring functional programming and Swift hosted by [Brandon Williams](https://twitter.com/mbrandonw) and [Stephen Celis](https://twitter.com/stephencelis). 440 | 441 | The ideas in this episode were first explored in [Episode #11](https://www.pointfree.co/episodes/ep11-composition-without-operators): 442 | 443 | 444 | video poster image 445 | 446 | 447 | ## License 448 | 449 | All modules are released under the MIT license. See [LICENSE](LICENSE) for details. 450 | -------------------------------------------------------------------------------- /Sources/Overture/Chain.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Forward composition of functions that return optionals. Useful for chaining operations that may fail. 3 | /// 4 | /// chain(String.init(validatingUTF8:), URL.init(string:)) 5 | /// // (UnsafePointer) -> URL? 6 | /// 7 | /// - Parameters: 8 | /// - f: A function that takes a value in `A` and returns an optional value in `B`. 9 | /// - a: An argument in `A`. 10 | /// - g: A function that takes a value in `B` and returns an optional value in `C`. 11 | /// - a: An argument in `B`. 12 | /// - Returns: A new function that takes a value in `A` and returns an optional value in `C`. 13 | /// - Note: This function is commonly seen in operator form as `>=>`. 14 | public func chain( 15 | _ f: @escaping (A) -> B?, 16 | _ g: @escaping (B) -> C? 17 | ) 18 | -> (A) -> C? { 19 | 20 | return { (a: A) -> C? in 21 | f(a).flatMap(g) 22 | } 23 | } 24 | 25 | public func chain( 26 | _ f: @escaping (A) -> B?, 27 | _ g: @escaping (B) -> C?, 28 | _ h: @escaping (C) -> D? 29 | ) 30 | -> (A) -> D? { 31 | 32 | return { (a: A) -> D? in 33 | f(a) 34 | .flatMap(g) 35 | .flatMap(h) 36 | } 37 | } 38 | 39 | public func chain( 40 | _ f: @escaping (A) -> B?, 41 | _ g: @escaping (B) -> C?, 42 | _ h: @escaping (C) -> D?, 43 | _ i: @escaping (D) -> E? 44 | ) 45 | -> (A) -> E? { 46 | 47 | return { (a: A) -> E? in 48 | f(a) 49 | .flatMap(g) 50 | .flatMap(h) 51 | .flatMap(i) 52 | } 53 | } 54 | 55 | public func chain( 56 | _ f: @escaping (A) -> B?, 57 | _ g: @escaping (B) -> C?, 58 | _ h: @escaping (C) -> D?, 59 | _ i: @escaping (D) -> E?, 60 | _ j: @escaping (E) -> F? 61 | ) 62 | -> (A) -> F? { 63 | 64 | return { (a: A) -> F? in 65 | f(a) 66 | .flatMap(g) 67 | .flatMap(h) 68 | .flatMap(i) 69 | .flatMap(j) 70 | } 71 | } 72 | 73 | public func chain( 74 | _ f: @escaping (A) -> B?, 75 | _ g: @escaping (B) -> C?, 76 | _ h: @escaping (C) -> D?, 77 | _ i: @escaping (D) -> E?, 78 | _ j: @escaping (E) -> F?, 79 | _ k: @escaping (F) -> G? 80 | ) 81 | -> (A) -> G? { 82 | 83 | return { (a: A) -> G? in 84 | f(a) 85 | .flatMap(g) 86 | .flatMap(h) 87 | .flatMap(i) 88 | .flatMap(j) 89 | .flatMap(k) 90 | } 91 | } 92 | 93 | public func chain( 94 | _ f: @escaping (A) throws -> B?, 95 | _ g: @escaping (B) throws -> C? 96 | ) 97 | -> (A) throws -> C? { 98 | 99 | return { (a: A) throws -> C? in 100 | try f(a).flatMap(g) 101 | } 102 | } 103 | 104 | public func chain( 105 | _ f: @escaping (A) throws -> B?, 106 | _ g: @escaping (B) throws -> C?, 107 | _ h: @escaping (C) throws -> D? 108 | ) 109 | -> (A) throws -> D? { 110 | 111 | return { (a: A) throws -> D? in 112 | try f(a) 113 | .flatMap(g) 114 | .flatMap(h) 115 | } 116 | } 117 | 118 | public func chain( 119 | _ f: @escaping (A) throws -> B?, 120 | _ g: @escaping (B) throws -> C?, 121 | _ h: @escaping (C) throws -> D?, 122 | _ i: @escaping (D) throws -> E? 123 | ) 124 | -> (A) throws -> E? { 125 | 126 | return { (a: A) throws -> E? in 127 | try f(a) 128 | .flatMap(g) 129 | .flatMap(h) 130 | .flatMap(i) 131 | } 132 | } 133 | 134 | public func chain( 135 | _ f: @escaping (A) throws -> B?, 136 | _ g: @escaping (B) throws -> C?, 137 | _ h: @escaping (C) throws -> D?, 138 | _ i: @escaping (D) throws -> E?, 139 | _ j: @escaping (E) throws -> F? 140 | ) 141 | -> (A) throws -> F? { 142 | 143 | return { (a: A) throws -> F? in 144 | try f(a) 145 | .flatMap(g) 146 | .flatMap(h) 147 | .flatMap(i) 148 | .flatMap(j) 149 | } 150 | } 151 | 152 | public func chain( 153 | _ f: @escaping (A) throws -> B?, 154 | _ g: @escaping (B) throws -> C?, 155 | _ h: @escaping (C) throws -> D?, 156 | _ i: @escaping (D) throws -> E?, 157 | _ j: @escaping (E) throws -> F?, 158 | _ k: @escaping (F) throws -> G? 159 | ) 160 | -> (A) throws -> G? { 161 | 162 | return { (a: A) throws -> G? in 163 | try f(a) 164 | .flatMap(g) 165 | .flatMap(h) 166 | .flatMap(i) 167 | .flatMap(j) 168 | .flatMap(k) 169 | } 170 | } 171 | 172 | /// Forward composition of functions that return arrays. 173 | /// 174 | /// - Parameters: 175 | /// - f: A function that takes a value in `A` and returns an array of `B`s. 176 | /// - g: A function that takes a value in `B` and returns an array of `C`s. 177 | /// - Returns: A new function that takes a value in `A` and returns an array of `C`s. 178 | public func chain( 179 | _ f: @escaping (A) -> [B], 180 | _ g: @escaping (B) -> [C] 181 | ) 182 | -> (A) -> [C] { 183 | 184 | return { (a: A) -> [C] in 185 | f(a).flatMap(g) 186 | } 187 | } 188 | 189 | public func chain( 190 | _ f: @escaping (A) -> [B], 191 | _ g: @escaping (B) -> [C], 192 | _ h: @escaping (C) -> [D] 193 | ) 194 | -> (A) -> [D] { 195 | 196 | return { (a: A) -> [D] in 197 | f(a) 198 | .flatMap(g) 199 | .flatMap(h) 200 | } 201 | } 202 | 203 | public func chain( 204 | _ f: @escaping (A) -> [B], 205 | _ g: @escaping (B) -> [C], 206 | _ h: @escaping (C) -> [D], 207 | _ i: @escaping (D) -> [E] 208 | ) 209 | -> (A) -> [E] { 210 | 211 | return { (a: A) -> [E] in 212 | f(a) 213 | .flatMap(g) 214 | .flatMap(h) 215 | .flatMap(i) 216 | } 217 | } 218 | 219 | public func chain( 220 | _ f: @escaping (A) -> [B], 221 | _ g: @escaping (B) -> [C], 222 | _ h: @escaping (C) -> [D], 223 | _ i: @escaping (D) -> [E], 224 | _ j: @escaping (E) -> [F] 225 | ) 226 | -> (A) -> [F] { 227 | 228 | return { (a: A) -> [F] in 229 | f(a) 230 | .flatMap(g) 231 | .flatMap(h) 232 | .flatMap(i) 233 | .flatMap(j) 234 | } 235 | } 236 | 237 | public func chain( 238 | _ f: @escaping (A) -> [B], 239 | _ g: @escaping (B) -> [C], 240 | _ h: @escaping (C) -> [D], 241 | _ i: @escaping (D) -> [E], 242 | _ j: @escaping (E) -> [F], 243 | _ k: @escaping (F) -> [G] 244 | ) 245 | -> (A) -> [G] { 246 | 247 | return { (a: A) -> [G] in 248 | f(a) 249 | .flatMap(g) 250 | .flatMap(h) 251 | .flatMap(i) 252 | .flatMap(j) 253 | .flatMap(k) 254 | } 255 | } 256 | 257 | public func chain( 258 | _ f: @escaping (A) throws -> [B], 259 | _ g: @escaping (B) throws -> [C] 260 | ) 261 | -> (A) throws -> [C] { 262 | 263 | return { (a: A) throws -> [C] in 264 | try f(a).flatMap(g) 265 | } 266 | } 267 | 268 | public func chain( 269 | _ f: @escaping (A) throws -> [B], 270 | _ g: @escaping (B) throws -> [C], 271 | _ h: @escaping (C) throws -> [D] 272 | ) 273 | -> (A) throws -> [D] { 274 | 275 | return { (a: A) throws -> [D] in 276 | try f(a) 277 | .flatMap(g) 278 | .flatMap(h) 279 | } 280 | } 281 | 282 | public func chain( 283 | _ f: @escaping (A) throws -> [B], 284 | _ g: @escaping (B) throws -> [C], 285 | _ h: @escaping (C) throws -> [D], 286 | _ i: @escaping (D) throws -> [E] 287 | ) 288 | -> (A) throws -> [E] { 289 | 290 | return { (a: A) throws -> [E] in 291 | try f(a) 292 | .flatMap(g) 293 | .flatMap(h) 294 | .flatMap(i) 295 | } 296 | } 297 | 298 | public func chain( 299 | _ f: @escaping (A) throws -> [B], 300 | _ g: @escaping (B) throws -> [C], 301 | _ h: @escaping (C) throws -> [D], 302 | _ i: @escaping (D) throws -> [E], 303 | _ j: @escaping (E) throws -> [F] 304 | ) 305 | -> (A) throws -> [F] { 306 | 307 | return { (a: A) throws -> [F] in 308 | try f(a) 309 | .flatMap(g) 310 | .flatMap(h) 311 | .flatMap(i) 312 | .flatMap(j) 313 | } 314 | } 315 | 316 | public func chain( 317 | _ f: @escaping (A) throws -> [B], 318 | _ g: @escaping (B) throws -> [C], 319 | _ h: @escaping (C) throws -> [D], 320 | _ i: @escaping (D) throws -> [E], 321 | _ j: @escaping (E) throws -> [F], 322 | _ k: @escaping (F) throws -> [G] 323 | ) 324 | -> (A) throws -> [G] { 325 | 326 | return { (a: A) throws -> [G] in 327 | try f(a) 328 | .flatMap(g) 329 | .flatMap(h) 330 | .flatMap(i) 331 | .flatMap(j) 332 | .flatMap(k) 333 | } 334 | } 335 | -------------------------------------------------------------------------------- /Sources/Overture/Combining.swift: -------------------------------------------------------------------------------- 1 | public func combining( 2 | _ getter: @escaping (Root) -> Value, 3 | _ combine: @escaping (Value, Value) -> NewValue 4 | ) 5 | -> (Value, Root) 6 | -> NewValue { 7 | return { value, root in combine(value, getter(root)) } 8 | } 9 | 10 | public func combining( 11 | _ getter: @escaping (Root) -> Value, 12 | _ combine: @escaping (inout Value, Value) -> Void 13 | ) 14 | -> (inout Value, Root) 15 | -> Void { 16 | return { value, root in combine(&value, getter(root)) } 17 | } 18 | 19 | public func their( 20 | _ getter: @escaping (Root) -> Value, 21 | _ combining: @escaping (Value, Value) -> NewValue 22 | ) 23 | -> (Root, Root) -> NewValue { 24 | return { combining(getter($0), getter($1)) } 25 | } 26 | 27 | public func their( 28 | _ getter: @escaping (Root) -> Value 29 | ) 30 | -> (Root, Root) -> Bool { 31 | return their(getter, <) 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Overture/Compose.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Backward composition of functions. 3 | /// 4 | /// - Parameters: 5 | /// - f: A function that takes a value in `B` and returns a value in `C`. 6 | /// - b: An argument in `B`. 7 | /// - g: A function that takes a value in `A` and returns a value in `B`. 8 | /// - a: An argument in `A`. 9 | /// - Returns: A new function that takes a value in `A` and returns a value in `C`. 10 | /// - Note: This function is commonly seen in operator form as `<<<`. 11 | public func compose( 12 | _ f: @escaping (B) -> C, 13 | _ g: @escaping (A) -> B 14 | ) 15 | -> (A) -> C { 16 | 17 | return { (a: A) -> C in 18 | f(g(a)) 19 | } 20 | } 21 | 22 | public func compose( 23 | _ f: @escaping (C) -> D, 24 | _ g: @escaping (B) -> C, 25 | _ h: @escaping (A) -> B 26 | ) 27 | -> (A) -> D { 28 | 29 | return { (a: A) -> D in 30 | f(g(h(a))) 31 | } 32 | } 33 | 34 | public func compose( 35 | _ f: @escaping (D) -> E, 36 | _ g: @escaping (C) -> D, 37 | _ h: @escaping (B) -> C, 38 | _ i: @escaping (A) -> B 39 | ) 40 | -> (A) -> E { 41 | 42 | return { (a: A) -> E in 43 | f(g(h(i(a)))) 44 | } 45 | } 46 | 47 | public func compose( 48 | _ f: @escaping (E) -> F, 49 | _ g: @escaping (D) -> E, 50 | _ h: @escaping (C) -> D, 51 | _ i: @escaping (B) -> C, 52 | _ j: @escaping (A) -> B 53 | ) 54 | -> (A) -> F { 55 | 56 | return { (a: A) -> F in 57 | f(g(h(i(j(a))))) 58 | } 59 | } 60 | 61 | public func compose( 62 | _ f: @escaping (F) -> G, 63 | _ g: @escaping (E) -> F, 64 | _ h: @escaping (D) -> E, 65 | _ i: @escaping (C) -> D, 66 | _ j: @escaping (B) -> C, 67 | _ k: @escaping (A) -> B 68 | ) 69 | -> (A) -> G { 70 | 71 | return { (a: A) -> G in 72 | f(g(h(i(j(k(a)))))) 73 | } 74 | } 75 | 76 | /// Backward composition of throwing functions. 77 | /// 78 | /// - Parameters: 79 | /// - f: A function that takes a value in `B` and returns a value in `C`. 80 | /// - b: An argument in `B`. 81 | /// - g: A function that takes a value in `A` and returns a value in `B`. 82 | /// - a: An argument in `A`. 83 | /// - Returns: A new function that takes a value in `A` and returns a value in `C`. 84 | /// - Note: This function is commonly seen in operator form as `<<<`. 85 | public func compose( 86 | _ f: @escaping (B) throws -> C, 87 | _ g: @escaping (A) throws -> B 88 | ) 89 | -> (A) throws -> C { 90 | 91 | return { (a: A) throws -> C in 92 | try f(g(a)) 93 | } 94 | } 95 | 96 | public func compose( 97 | _ f: @escaping (C) throws -> D, 98 | _ g: @escaping (B) throws -> C, 99 | _ h: @escaping (A) throws -> B 100 | ) 101 | -> (A) throws -> D { 102 | 103 | return { (a: A) throws -> D in 104 | try f(g(h(a))) 105 | } 106 | } 107 | 108 | public func compose( 109 | _ f: @escaping (D) throws -> E, 110 | _ g: @escaping (C) throws -> D, 111 | _ h: @escaping (B) throws -> C, 112 | _ i: @escaping (A) throws -> B 113 | ) 114 | -> (A) throws -> E { 115 | 116 | return { (a: A) throws -> E in 117 | try f(g(h(i(a)))) 118 | } 119 | } 120 | 121 | public func compose( 122 | _ f: @escaping (E) throws -> F, 123 | _ g: @escaping (D) throws -> E, 124 | _ h: @escaping (C) throws -> D, 125 | _ i: @escaping (B) throws -> C, 126 | _ j: @escaping (A) throws -> B 127 | ) 128 | -> (A) throws -> F { 129 | 130 | return { (a: A) throws -> F in 131 | try f(g(h(i(j(a))))) 132 | } 133 | } 134 | 135 | public func compose( 136 | _ f: @escaping (F) throws -> G, 137 | _ g: @escaping (E) throws -> F, 138 | _ h: @escaping (D) throws -> E, 139 | _ i: @escaping (C) throws -> D, 140 | _ j: @escaping (B) throws -> C, 141 | _ k: @escaping (A) throws -> B 142 | ) 143 | -> (A) throws -> G { 144 | 145 | return { (a: A) throws -> G in 146 | try f(g(h(i(j(k(a)))))) 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Sources/Overture/Concat.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Composes an array of functions that take and return the same type. 3 | /// 4 | /// - Parameters: 5 | /// - fs: Zero or more functions to apply in order. 6 | /// - Returns: A new function that applies every function given as input in order. 7 | /// - Note: This function is commonly seen in operator form as `<>`. 8 | public func concat( 9 | _ fs: [(A) -> A] 10 | ) 11 | -> (A) -> A { 12 | 13 | return { (a: A) -> A in 14 | fs.reduce(a) { a, f in f(a) } 15 | } 16 | } 17 | 18 | /// Forward composition of functions that take and return the same type. 19 | /// 20 | /// - Parameters: 21 | /// - fs: Zero or more functions to apply in order. 22 | /// - fz: A final, optional, terminating function for trailing closure syntax. 23 | /// - a: The argument to the final function. 24 | /// - Returns: A new function that applies every function given as input in order. 25 | /// - Note: This function is commonly seen in operator form as `<>`. 26 | public func concat( 27 | _ fs: ((A) -> A)..., 28 | and fz: @escaping (_ a: A) -> A = { $0 } 29 | ) 30 | -> (A) -> A { 31 | 32 | return concat(fs + [fz]) 33 | } 34 | 35 | /// Composes an array of throwing functions that take and return the same type. 36 | /// 37 | /// - Parameters: 38 | /// - fs: Zero or more functions to apply in order. 39 | /// - Returns: A new function that applies every function given as input in order. 40 | /// - Note: This function is commonly seen in operator form as `<>`. 41 | public func concat( 42 | _ fs: [(A) throws -> A] 43 | ) 44 | -> (A) throws -> A { 45 | 46 | return { (a: A) throws -> A in 47 | try fs.reduce(a) { a, f in try f(a) } 48 | } 49 | } 50 | 51 | /// Forward composition of throwing functions that take and return the same type. 52 | /// 53 | /// - Parameters: 54 | /// - fs: Zero or more functions to apply in order. 55 | /// - fz: A final, optional, terminating function for trailing closure syntax. 56 | /// - a: The argument to the final function. 57 | /// - Returns: A new function that applies every function given as input in order. 58 | /// - Note: This function is commonly seen in operator form as `<>`. 59 | public func concat( 60 | _ fs: ((A) throws -> A)..., 61 | and fz: @escaping (_ a: A) throws -> A = { $0 } 62 | ) 63 | -> (A) throws -> A { 64 | 65 | return concat(fs + [fz]) 66 | } 67 | 68 | /// Composes an array of mutable functions that mutate the same type. 69 | /// 70 | /// - Parameters: 71 | /// - fs: Zero or more functions to apply in order. 72 | /// - Returns: A new function that applies every function given as input in order. 73 | /// - Note: This function is commonly seen in operator form as `<>`. 74 | public func concat( 75 | _ fs: [(inout A) -> Void] 76 | ) 77 | -> (inout A) -> Void { 78 | 79 | return { (a: inout A) -> Void in 80 | fs.forEach { f in f(&a) } 81 | } 82 | } 83 | 84 | /// Forward composition of mutable functions that mutate the same type. 85 | /// 86 | /// - Parameters: 87 | /// - fs: Zero or more functions to apply in order. 88 | /// - fz: A final, optional, terminating function for trailing closure syntax. 89 | /// - a: The argument to the final function. 90 | /// - Returns: A new function that applies every function given as input in order. 91 | /// - Note: This function is commonly seen in operator form as `<>`. 92 | public func concat( 93 | _ fs: ((inout A) -> Void)..., 94 | and fz: @escaping (_ a: inout A) -> Void = { _ in } 95 | ) 96 | -> (inout A) -> Void { 97 | 98 | return concat(fs + [fz]) 99 | } 100 | 101 | /// Composes an array of mutable, throwing functions that mutate the same type. 102 | /// 103 | /// - Parameters: 104 | /// - fs: Zero or more functions to apply in order. 105 | /// - Returns: A new function that applies every function given as input in order. 106 | /// - Note: This function is commonly seen in operator form as `<>`. 107 | public func concat( 108 | _ fs: [(inout A) throws -> Void] 109 | ) 110 | -> (inout A) throws -> Void { 111 | 112 | return { (a: inout A) throws -> Void in 113 | try fs.forEach { f in try f(&a) } 114 | } 115 | } 116 | 117 | /// Forward composition of mutable, throwing functions that mutate the same type. 118 | /// 119 | /// - Parameters: 120 | /// - fs: Zero or more functions to apply in order. 121 | /// - fz: A final, optional, terminating function for trailing closure syntax. 122 | /// - a: The argument to the final function. 123 | /// - Returns: A new function that applies every function given as input in order. 124 | /// - Note: This function is commonly seen in operator form as `<>`. 125 | public func concat( 126 | _ fs: ((inout A) throws -> Void)..., 127 | and fz: @escaping (_ a: inout A) throws -> Void = { _ in } 128 | ) 129 | -> (inout A) throws -> Void { 130 | 131 | return concat(fs + [fz]) 132 | } 133 | 134 | /// Composes an array of reference-mutable functions that mutate the same type. 135 | /// 136 | /// - Parameters: 137 | /// - fs: Zero or more functions to apply in order. 138 | /// - Returns: A new function that applies every function given as input in order. 139 | /// - Note: This function is commonly seen in operator form as `<>`. 140 | public func concat( 141 | _ fs: [(A) -> Void] 142 | ) 143 | -> (A) -> Void { 144 | 145 | return { (a: A) -> Void in 146 | fs.forEach { f in f(a) } 147 | } 148 | } 149 | 150 | /// Forward composition of reference-mutable functions that mutate the same type. 151 | /// 152 | /// - Parameters: 153 | /// - fs: Zero or more functions to apply in order. 154 | /// - Returns: A new function that applies every function given as input in order. 155 | /// - Note: This function is commonly seen in operator form as `<>`. 156 | public func concat( 157 | _ fs: ((A) -> Void)..., 158 | and fz: @escaping (_ a: A) -> Void = { _ in } 159 | ) 160 | -> (A) -> Void { 161 | 162 | return concat(fs + [fz]) 163 | } 164 | 165 | /// Composes an array of reference-mutable, throwing functions that mutate the same type. 166 | /// 167 | /// - Parameters: 168 | /// - fs: Zero or more functions to apply in order. 169 | /// - Returns: A new function that applies every function given as input in order. 170 | /// - Note: This function is commonly seen in operator form as `<>`. 171 | public func concat( 172 | _ fs: [(A) throws -> Void] 173 | ) 174 | -> (A) throws -> Void { 175 | 176 | return { (a: A) throws -> Void in 177 | try fs.forEach { f in try f(a) } 178 | } 179 | } 180 | 181 | /// Forward composition of reference-mutable, throwing functions that mutate the same type. 182 | /// 183 | /// - Parameters: 184 | /// - fs: Zero or more functions to apply in order. 185 | /// - Returns: A new function that applies every function given as input in order. 186 | /// - Note: This function is commonly seen in operator form as `<>`. 187 | public func concat( 188 | _ fs: ((A) throws -> Void)..., 189 | and fz: @escaping (_ a: A) throws -> Void = { _ in } 190 | ) 191 | -> (A) throws -> Void { 192 | 193 | return concat(fs + [fz]) 194 | } 195 | -------------------------------------------------------------------------------- /Sources/Overture/Curry.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Curries a function of two arguments. 3 | /// 4 | /// - Parameter function: A function of two arguments. 5 | /// - Returns: A curried function. 6 | public func curry (_ function: @escaping (A1, A2) -> R) -> (A1) -> (A2) -> R { 7 | return { (a1: A1) -> (A2) -> R in { (a2: A2) -> R in function(a1, a2) } } 8 | } 9 | 10 | /// Curries a throwing function of two arguments. 11 | /// 12 | /// - Parameter function: A throwing function of two arguments. 13 | /// - Returns: A curried, final-throwing function. 14 | public func curry (_ function: @escaping (A1, A2) throws -> R) -> (A1) -> (A2) throws -> R { 15 | return { (a1: A1) -> (A2) throws -> R in { (a2: A2) throws -> R in try function(a1, a2) } } 16 | } 17 | 18 | public func curry (_ function: @escaping (A1, A2, A3) -> R) -> (A1) -> (A2) -> (A3) -> R { 19 | return { (a1: A1) -> (A2) -> (A3) -> R in { (a2: A2) -> (A3) -> R in { (a3: A3) -> R in function(a1, a2, a3) } } } 20 | } 21 | 22 | public func curry (_ function: @escaping (A1, A2, A3) throws -> R) -> (A1) -> (A2) -> (A3) throws -> R { 23 | return { (a1: A1) -> (A2) -> (A3) throws -> R in { (a2: A2) -> (A3) throws -> R in { (a3: A3) throws -> R in try function(a1, a2, a3) } } } 24 | } 25 | 26 | public func curry (_ function: @escaping (A1, A2, A3, A4) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> R { 27 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> R in { (a2: A2) -> (A3) -> (A4) -> R in { (a3: A3) -> (A4) -> R in { (a4: A4) -> R in function(a1, a2, a3, a4) } } } } 28 | } 29 | 30 | public func curry (_ function: @escaping (A1, A2, A3, A4) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) throws -> R { 31 | return { (a1: A1) -> (A2) -> (A3) -> (A4) throws -> R in { (a2: A2) -> (A3) -> (A4) throws -> R in { (a3: A3) -> (A4) throws -> R in { (a4: A4) throws -> R in try function(a1, a2, a3, a4) } } } } 32 | } 33 | 34 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> R { 35 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> R in { (a3: A3) -> (A4) -> (A5) -> R in { (a4: A4) -> (A5) -> R in { (a5: A5) -> R in function(a1, a2, a3, a4, a5) } } } } } 36 | } 37 | 38 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) throws -> R { 39 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) throws -> R in { (a3: A3) -> (A4) -> (A5) throws -> R in { (a4: A4) -> (A5) throws -> R in { (a5: A5) throws -> R in try function(a1, a2, a3, a4, a5) } } } } } 40 | } 41 | 42 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> R { 43 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> R in { (a4: A4) -> (A5) -> (A6) -> R in { (a5: A5) -> (A6) -> R in { (a6: A6) -> R in function(a1, a2, a3, a4, a5, a6) } } } } } } 44 | } 45 | 46 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) throws -> R { 47 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) throws -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) throws -> R in { (a4: A4) -> (A5) -> (A6) throws -> R in { (a5: A5) -> (A6) throws -> R in { (a6: A6) throws -> R in try function(a1, a2, a3, a4, a5, a6) } } } } } } 48 | } 49 | 50 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> R { 51 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> R in { (a5: A5) -> (A6) -> (A7) -> R in { (a6: A6) -> (A7) -> R in { (a7: A7) -> R in function(a1, a2, a3, a4, a5, a6, a7) } } } } } } } 52 | } 53 | 54 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) throws -> R { 55 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) throws -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) throws -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) throws -> R in { (a5: A5) -> (A6) -> (A7) throws -> R in { (a6: A6) -> (A7) throws -> R in { (a7: A7) throws -> R in try function(a1, a2, a3, a4, a5, a6, a7) } } } } } } } 56 | } 57 | 58 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> R { 59 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> R in { (a6: A6) -> (A7) -> (A8) -> R in { (a7: A7) -> (A8) -> R in { (a8: A8) -> R in function(a1, a2, a3, a4, a5, a6, a7, a8) } } } } } } } } 60 | } 61 | 62 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) throws -> R { 63 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) throws -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) throws -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) throws -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) throws -> R in { (a6: A6) -> (A7) -> (A8) throws -> R in { (a7: A7) -> (A8) throws -> R in { (a8: A8) throws -> R in try function(a1, a2, a3, a4, a5, a6, a7, a8) } } } } } } } } 64 | } 65 | 66 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> R { 67 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> R in { (a7: A7) -> (A8) -> (A9) -> R in { (a8: A8) -> (A9) -> R in { (a9: A9) -> R in function(a1, a2, a3, a4, a5, a6, a7, a8, a9) } } } } } } } } } 68 | } 69 | 70 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) throws -> R { 71 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) throws -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) throws -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) throws -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) throws -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) throws -> R in { (a7: A7) -> (A8) -> (A9) throws -> R in { (a8: A8) -> (A9) throws -> R in { (a9: A9) throws -> R in try function(a1, a2, a3, a4, a5, a6, a7, a8, a9) } } } } } } } } } 72 | } 73 | 74 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> R { 75 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> R in { (a8: A8) -> (A9) -> (A10) -> R in { (a9: A9) -> (A10) -> R in { (a10: A10) -> R in function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) } } } } } } } } } } 76 | } 77 | 78 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) throws -> R { 79 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) throws -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) throws -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) throws -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) throws -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) throws -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) throws -> R in { (a8: A8) -> (A9) -> (A10) throws -> R in { (a9: A9) -> (A10) throws -> R in { (a10: A10) throws -> R in try function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) } } } } } } } } } } 80 | } 81 | 82 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> R { 83 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> R in { (a9: A9) -> (A10) -> (A11) -> R in { (a10: A10) -> (A11) -> R in { (a11: A11) -> R in function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) } } } } } } } } } } } 84 | } 85 | 86 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) throws -> R { 87 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) throws -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) throws -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) throws -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) throws -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) throws -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) throws -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) throws -> R in { (a9: A9) -> (A10) -> (A11) throws -> R in { (a10: A10) -> (A11) throws -> R in { (a11: A11) throws -> R in try function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) } } } } } } } } } } } 88 | } 89 | 90 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> R { 91 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) -> R in { (a10: A10) -> (A11) -> (A12) -> R in { (a11: A11) -> (A12) -> R in { (a12: A12) -> R in function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) } } } } } } } } } } } } 92 | } 93 | 94 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) throws -> R { 95 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) throws -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) throws -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) throws -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) throws -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) throws -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) throws -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) throws -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) throws -> R in { (a10: A10) -> (A11) -> (A12) throws -> R in { (a11: A11) -> (A12) throws -> R in { (a12: A12) throws -> R in try function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) } } } } } } } } } } } } 96 | } 97 | 98 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> R { 99 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) -> (A13) -> R in { (a10: A10) -> (A11) -> (A12) -> (A13) -> R in { (a11: A11) -> (A12) -> (A13) -> R in { (a12: A12) -> (A13) -> R in { (a13: A13) -> R in function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) } } } } } } } } } } } } } 100 | } 101 | 102 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) throws -> R { 103 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) throws -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) throws -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) throws -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) throws -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) throws -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) throws -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) throws -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) -> (A13) throws -> R in { (a10: A10) -> (A11) -> (A12) -> (A13) throws -> R in { (a11: A11) -> (A12) -> (A13) throws -> R in { (a12: A12) -> (A13) throws -> R in { (a13: A13) throws -> R in try function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) } } } } } } } } } } } } } 104 | } 105 | 106 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> R { 107 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> R in { (a10: A10) -> (A11) -> (A12) -> (A13) -> (A14) -> R in { (a11: A11) -> (A12) -> (A13) -> (A14) -> R in { (a12: A12) -> (A13) -> (A14) -> R in { (a13: A13) -> (A14) -> R in { (a14: A14) -> R in function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) } } } } } } } } } } } } } } 108 | } 109 | 110 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) throws -> R { 111 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) throws -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) throws -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) throws -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) throws -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) throws -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) throws -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) throws -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) throws -> R in { (a10: A10) -> (A11) -> (A12) -> (A13) -> (A14) throws -> R in { (a11: A11) -> (A12) -> (A13) -> (A14) throws -> R in { (a12: A12) -> (A13) -> (A14) throws -> R in { (a13: A13) -> (A14) throws -> R in { (a14: A14) throws -> R in try function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) } } } } } } } } } } } } } } 112 | } 113 | 114 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> R { 115 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> R in { (a10: A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> R in { (a11: A11) -> (A12) -> (A13) -> (A14) -> (A15) -> R in { (a12: A12) -> (A13) -> (A14) -> (A15) -> R in { (a13: A13) -> (A14) -> (A15) -> R in { (a14: A14) -> (A15) -> R in { (a15: A15) -> R in function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) } } } } } } } } } } } } } } } 116 | } 117 | 118 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) throws -> R { 119 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) throws -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) throws -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) throws -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) throws -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) throws -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) throws -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) throws -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) throws -> R in { (a10: A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) throws -> R in { (a11: A11) -> (A12) -> (A13) -> (A14) -> (A15) throws -> R in { (a12: A12) -> (A13) -> (A14) -> (A15) throws -> R in { (a13: A13) -> (A14) -> (A15) throws -> R in { (a14: A14) -> (A15) throws -> R in { (a15: A15) throws -> R in try function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) } } } } } } } } } } } } } } } 120 | } 121 | 122 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> R { 123 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> R in { (a10: A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> R in { (a11: A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> R in { (a12: A12) -> (A13) -> (A14) -> (A15) -> (A16) -> R in { (a13: A13) -> (A14) -> (A15) -> (A16) -> R in { (a14: A14) -> (A15) -> (A16) -> R in { (a15: A15) -> (A16) -> R in { (a16: A16) -> R in function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) } } } } } } } } } } } } } } } } 124 | } 125 | 126 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) throws -> R { 127 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) throws -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) throws -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) throws -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) throws -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) throws -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) throws -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) throws -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) throws -> R in { (a10: A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) throws -> R in { (a11: A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) throws -> R in { (a12: A12) -> (A13) -> (A14) -> (A15) -> (A16) throws -> R in { (a13: A13) -> (A14) -> (A15) -> (A16) throws -> R in { (a14: A14) -> (A15) -> (A16) throws -> R in { (a15: A15) -> (A16) throws -> R in { (a16: A16) throws -> R in try function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) } } } } } } } } } } } } } } } } 128 | } 129 | 130 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R { 131 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R in { (a10: A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R in { (a11: A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R in { (a12: A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R in { (a13: A13) -> (A14) -> (A15) -> (A16) -> (A17) -> R in { (a14: A14) -> (A15) -> (A16) -> (A17) -> R in { (a15: A15) -> (A16) -> (A17) -> R in { (a16: A16) -> (A17) -> R in { (a17: A17) -> R in function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17) } } } } } } } } } } } } } } } } } 132 | } 133 | 134 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R { 135 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a10: A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a11: A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a12: A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a13: A13) -> (A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a14: A14) -> (A15) -> (A16) -> (A17) throws -> R in { (a15: A15) -> (A16) -> (A17) throws -> R in { (a16: A16) -> (A17) throws -> R in { (a17: A17) throws -> R in try function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17) } } } } } } } } } } } } } } } } } 136 | } 137 | 138 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R { 139 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a10: A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a11: A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a12: A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a13: A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a14: A14) -> (A15) -> (A16) -> (A17) -> (A18) -> R in { (a15: A15) -> (A16) -> (A17) -> (A18) -> R in { (a16: A16) -> (A17) -> (A18) -> R in { (a17: A17) -> (A18) -> R in { (a18: A18) -> R in function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18) } } } } } } } } } } } } } } } } } } 140 | } 141 | 142 | public func curry (_ function: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) throws -> R) -> (A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R { 143 | return { (a1: A1) -> (A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a2: A2) -> (A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a3: A3) -> (A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a4: A4) -> (A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a5: A5) -> (A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a6: A6) -> (A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a7: A7) -> (A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a8: A8) -> (A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a9: A9) -> (A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a10: A10) -> (A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a11: A11) -> (A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a12: A12) -> (A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a13: A13) -> (A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a14: A14) -> (A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a15: A15) -> (A16) -> (A17) -> (A18) throws -> R in { (a16: A16) -> (A17) -> (A18) throws -> R in { (a17: A17) -> (A18) throws -> R in { (a18: A18) throws -> R in try function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18) } } } } } } } } } } } } } } } } } } 144 | } 145 | -------------------------------------------------------------------------------- /Sources/Overture/Flip.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Flips the argument order of a zero-argument, curried function. 3 | /// 4 | /// - Parameter f: A zero-argument, curried function. 5 | /// - Returns: A curried function with the zero-argument surfaced. 6 | public func flip(_ function: @escaping (A) -> () -> B) 7 | -> () -> (A) -> B { 8 | 9 | return { () -> (A) -> B in 10 | { (a: A) -> B in 11 | function(a)() 12 | } 13 | } 14 | } 15 | 16 | /// Flips the argument order of a curried function. 17 | /// 18 | /// - Parameter function: A curried function. 19 | /// - Returns: A curried function with its first two arguments flipped. 20 | public func flip(_ function: @escaping (A) -> (B) -> C) 21 | -> (B) -> (A) -> C { 22 | 23 | return { (b: B) -> (A) -> C in 24 | { (a: A) -> C in 25 | function(a)(b) 26 | } 27 | } 28 | } 29 | 30 | /// Flips the argument order of a two-argument curried function. 31 | /// 32 | /// - Parameter function: A two-argument, curried function. 33 | /// - Returns: A curried function with its first two arguments flipped. 34 | public func flip(_ function: @escaping (A) -> (B, C) -> D) 35 | -> (B, C) -> (A) -> D { 36 | 37 | return { (b: B, c: C) -> (A) -> D in 38 | { (a: A) -> D in 39 | function(a)(b, c) 40 | } 41 | } 42 | } 43 | 44 | /// Flips the argument order of a three-argument curried function. 45 | /// 46 | /// - Parameter function: A three-argument, curried function. 47 | /// - Returns: A curried function with its first two arguments flipped. 48 | public func flip(_ function: @escaping (A) -> (B, C, D) -> E) 49 | -> (B, C, D) -> (A) -> E { 50 | 51 | return { (b: B, c: C, d: D) -> (A) -> E in 52 | { (a: A) -> E in 53 | function(a)(b, c, d) 54 | } 55 | } 56 | } 57 | 58 | /// Flips the argument order of a four-argument curried function. 59 | /// 60 | /// - Parameter function: A four-argument, curried function. 61 | /// - Returns: A curried function with its first two arguments flipped. 62 | public func flip(_ function: @escaping (A) -> (B, C, D, E) -> F) 63 | -> (B, C, D, E) -> (A) -> F { 64 | 65 | return { (b: B, c: C, d: D, e: E) -> (A) -> F in 66 | { (a: A) -> F in 67 | function(a)(b, c, d, e) 68 | } 69 | } 70 | } 71 | 72 | /// Flips the argument order of a five-argument curried function. 73 | /// 74 | /// - Parameter function: A five-argument, curried function. 75 | /// - Returns: A curried function with its first two arguments flipped. 76 | public func flip(_ function: @escaping (A) -> (B, C, D, E, F) -> G) 77 | -> (B, C, D, E, F) -> (A) -> G { 78 | 79 | return { (b: B, c: C, d: D, e: E, f: F) -> (A) -> G in 80 | { (a: A) -> G in 81 | function(a)(b, c, d, e, f) 82 | } 83 | } 84 | } 85 | 86 | /// Flips the argument order of a throwing, zero-argument, curried function. 87 | /// 88 | /// - Parameter function: A throwing, zero-argument, curried function. 89 | /// - Returns: A throwing, curried function with the zero-argument surfaced. 90 | public func flip(_ function: @escaping (A) -> () throws -> B) 91 | -> () -> (A) throws -> B { 92 | 93 | return { () -> (A) throws -> B in 94 | { (a: A) throws -> B in 95 | try function(a)() 96 | } 97 | } 98 | } 99 | 100 | /// Flips the argument order of a throwing, curried function. 101 | /// 102 | /// - Parameter function: A throwing, curried function. 103 | /// - Returns: A throwing, curried function with its first two arguments flipped. 104 | public func flip(_ function: @escaping (A) -> (B) throws -> C) 105 | -> (B) -> (A) throws -> C { 106 | 107 | return { (b: B) -> (A) throws -> C in 108 | { (a: A) throws -> C in 109 | try function(a)(b) 110 | } 111 | } 112 | } 113 | 114 | /// Flips the argument order of a two-argument curried function. 115 | /// 116 | /// - Parameter function: A throwing, two-argument, curried function. 117 | /// - Returns: A curried function with its first two arguments flipped. 118 | public func flip(_ function: @escaping (A) -> (B, C) throws -> D) 119 | -> (B, C) -> (A) throws -> D { 120 | 121 | return { (b: B, c: C) -> (A) throws -> D in 122 | { (a: A) throws -> D in 123 | try function(a)(b, c) 124 | } 125 | } 126 | } 127 | 128 | /// Flips the argument order of a three-argument curried function. 129 | /// 130 | /// - Parameter function: A throwing, three-argument, curried function. 131 | /// - Returns: A curried function with its first two arguments flipped. 132 | public func flip(_ function: @escaping (A) -> (B, C, D) throws -> E) 133 | -> (B, C, D) -> (A) throws -> E { 134 | 135 | return { (b: B, c: C, d: D) -> (A) throws -> E in 136 | { (a: A) throws -> E in 137 | try function(a)(b, c, d) 138 | } 139 | } 140 | } 141 | 142 | /// Flips the argument order of a four-argument curried function. 143 | /// 144 | /// - Parameter function: A throwing, four-argument, curried function. 145 | /// - Returns: A curried function with its first two arguments flipped. 146 | public func flip(_ function: @escaping (A) -> (B, C, D, E) throws -> F) 147 | -> (B, C, D, E) -> (A) throws -> F { 148 | 149 | return { (b: B, c: C, d: D, e: E) -> (A) throws -> F in 150 | { (a: A) throws -> F in 151 | try function(a)(b, c, d, e) 152 | } 153 | } 154 | } 155 | 156 | /// Flips the argument order of a five-argument curried function. 157 | /// 158 | /// - Parameter function: A throwing, five-argument, curried function. 159 | /// - Returns: A curried function with its first two arguments flipped. 160 | public func flip(_ function: @escaping (A) -> (B, C, D, E, F) throws -> G) 161 | -> (B, C, D, E, F) -> (A) throws -> G { 162 | 163 | return { (b: B, c: C, d: D, e: E, f: F) -> (A) throws -> G in 164 | { (a: A) throws -> G in 165 | try function(a)(b, c, d, e, f) 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /Sources/Overture/KeyPath.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Produces a getter function for a given key path. Useful for composing property access with functions. 3 | /// 4 | /// get(\String.count) 5 | /// // (String) -> Int 6 | /// 7 | /// - Parameter keyPath: A key path. 8 | /// - Returns: A getter function. 9 | public func get(_ keyPath: KeyPath) -> (Root) -> Value { 10 | return { root in root[keyPath: keyPath] } 11 | } 12 | 13 | /// Produces an immutable setter function for a given key path. Useful for composing property changes. 14 | /// 15 | /// - Parameter keyPath: A key path. 16 | /// - Returns: A setter function. 17 | public func prop( 18 | _ keyPath: WritableKeyPath 19 | ) 20 | -> (@escaping (Value) -> Value) 21 | -> (Root) -> Root { 22 | 23 | return { update in 24 | { root in 25 | var copy = root 26 | copy[keyPath: keyPath] = update(copy[keyPath: keyPath]) 27 | return copy 28 | } 29 | } 30 | } 31 | 32 | /// Produces an immutable setter function for a given key path and update function. 33 | /// 34 | /// - Parameters 35 | /// - keyPath: A key path. 36 | /// - update: An update function. 37 | /// - Returns: A setter function. 38 | public func over( 39 | _ keyPath: WritableKeyPath, 40 | _ update: @escaping (Value) -> Value 41 | ) 42 | -> (Root) -> Root { 43 | 44 | return prop(keyPath)(update) 45 | } 46 | 47 | /// Produces an immutable setter function for a given key path and constant value. 48 | /// 49 | /// - Parameters: 50 | /// - keyPath: A key path. 51 | /// - value: A new value. 52 | /// - Returns: A setter function. 53 | public func set( 54 | _ keyPath: WritableKeyPath, 55 | _ value: Value 56 | ) 57 | -> (Root) -> Root { 58 | 59 | return over(keyPath) { _ in value } 60 | } 61 | 62 | // MARK: - Mutation 63 | 64 | /// Produces an in-place setter function for a given key path. Useful for composing value property changes efficiently. 65 | /// 66 | /// - Parameter keyPath: A writable key path. 67 | /// - Returns: A mutable setter function. 68 | public func mprop( 69 | _ keyPath: WritableKeyPath 70 | ) 71 | -> (@escaping (inout Value) -> Void) 72 | -> (inout Root) -> Void { 73 | 74 | return { update in 75 | { root in 76 | update(&root[keyPath: keyPath]) 77 | } 78 | } 79 | } 80 | 81 | /// Uncurried `mver`. Takes a key path and update function all at once. 82 | /// 83 | /// - Parameters: 84 | /// - keyPath: A writable key path. 85 | /// - update: An update function for a given value. 86 | /// - Returns: A value-mutable setter function. 87 | public func mver( 88 | _ keyPath: WritableKeyPath, 89 | _ update: @escaping (inout Value) -> Void 90 | ) 91 | -> (inout Root) -> Void { 92 | 93 | return mprop(keyPath)(update) 94 | } 95 | 96 | /// Produces a reference-mutable setter function for a given key path to a reference. Useful for composing reference property changes efficiently. 97 | /// 98 | /// - Parameter keyPath: A reference-writable key path. 99 | /// - Returns: A reference-mutable setter function. 100 | public func mprop( 101 | _ keyPath: ReferenceWritableKeyPath 102 | ) 103 | -> (@escaping (Value) -> Void) 104 | -> (Root) -> Void 105 | where Value: AnyObject { 106 | 107 | return { update in 108 | { root in 109 | update(root[keyPath: keyPath]) 110 | } 111 | } 112 | } 113 | 114 | /// Uncurried `mver`. Takes a key path and update function all at once. 115 | /// 116 | /// - Parameters: 117 | /// - keyPath: A reference-writable key path. 118 | /// - update: An update function for a given value. 119 | /// - Returns: A reference-mutable setter function. 120 | public func mverObject( 121 | _ keyPath: ReferenceWritableKeyPath, 122 | _ update: @escaping (Value) -> Void 123 | ) 124 | -> (Root) -> Void 125 | where Value: AnyObject { 126 | 127 | return mprop(keyPath)(update) 128 | } 129 | 130 | /// Produces an reference-mutable setter function for a given key path to a value. Useful for composing reference property changes efficiently. 131 | /// 132 | /// - Parameter keyPath: A key path. 133 | /// - Returns: A setter function. 134 | public func mprop( 135 | _ keyPath: ReferenceWritableKeyPath 136 | ) 137 | -> (@escaping (inout Value) -> Void) 138 | -> (Root) -> Void { 139 | 140 | return { update in 141 | { root in 142 | update(&root[keyPath: keyPath]) 143 | } 144 | } 145 | } 146 | 147 | /// Uncurried `mver`. Takes a key path and update function all at once. 148 | /// 149 | /// - Parameters: 150 | /// - keyPath: A reference-writable key path. 151 | /// - update: An update function for a given value. 152 | /// - Returns: A reference-mutable setter function. 153 | public func mver( 154 | _ keyPath: ReferenceWritableKeyPath, 155 | _ update: @escaping (inout Value) -> Void 156 | ) 157 | -> (Root) -> Void { 158 | 159 | return mprop(keyPath)(update) 160 | } 161 | 162 | /// Produces a value-mutable setter function for a given key path and new value. 163 | /// 164 | /// - Parameters: 165 | /// - keyPath: A writable key path. 166 | /// - value: A new value. 167 | /// - Returns: A value-mutable setter function. 168 | public func mut( 169 | _ keyPath: WritableKeyPath, 170 | _ value: Value 171 | ) 172 | -> (inout Root) -> Void { 173 | 174 | return mver(keyPath) { $0 = value } 175 | } 176 | 177 | /// Produces a reference-mutable setter function for a given key path and new value. 178 | /// 179 | /// - Parameters: 180 | /// - keyPath: A reference-writable key path. 181 | /// - value: A new value. 182 | /// - Returns: A reference-mutable setter function. 183 | public func mut( 184 | _ keyPath: ReferenceWritableKeyPath, 185 | _ value: Value 186 | ) 187 | -> (Root) -> Void { 188 | 189 | return mver(keyPath) { $0 = value } 190 | } 191 | -------------------------------------------------------------------------------- /Sources/Overture/Optional.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Free `map` on optionals for function composition. 3 | /// 4 | /// - Parameter transform: A transform function. 5 | /// - Returns: An optional with its wrapped value transformed. 6 | public func map( 7 | _ transform: @escaping (A) -> B 8 | ) 9 | -> (A?) -> B? { 10 | 11 | return { $0.map(transform) } 12 | } 13 | 14 | /// Free `map` on optionals for throwing function composition. 15 | /// 16 | /// - Parameter transform: A transform function. 17 | /// - Returns: An optional with its wrapped value transformed. 18 | public func map( 19 | _ transform: @escaping (A) throws -> B 20 | ) 21 | -> (A?) throws -> B? { 22 | 23 | return { try $0.map(transform) } 24 | } 25 | 26 | 27 | /// Transforms a pair of optionals into an optional pair. 28 | /// 29 | /// - Parameters: 30 | /// - optional1: An optional value. 31 | /// - optional2: Another optional value. 32 | /// - Returns: An optional pair of values. 33 | public func zip(_ optional1: A?, _ optional2: B?) -> (A, B)? { 34 | guard let a = optional1, let b = optional2 else { return nil } 35 | return (a, b) 36 | } 37 | 38 | /// Transforms a pair of optionals into a new optional value. 39 | /// 40 | /// - Parameters: 41 | /// - transform: A transform function. 42 | /// - optional1: An optional value. 43 | /// - optional2: Another optional value. 44 | /// - Returns: A transformed optional value. 45 | public func zip( 46 | with transform: (A, B) -> Z, 47 | _ optional1: A?, 48 | _ optional2: B? 49 | ) -> Z? { 50 | return zip(optional1, optional2).map(transform) 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Overture/Pipe.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Forward composition of functions. 3 | /// 4 | /// - Parameters: 5 | /// - f: A function that takes a value in `A` and returns a value in `B`. 6 | /// - a: An argument in `A`. 7 | /// - g: A function that takes a value in `B` and returns a value in `C`. 8 | /// - b: An argument in `B`. 9 | /// - Returns: A new function that takes a value in `A` and returns a value in `C`. 10 | /// - Note: This function is commonly seen in operator form as `>>>`. 11 | public func pipe( 12 | _ f: @escaping (_ a: A) -> B, 13 | _ g: @escaping (_ b: B) -> C 14 | ) 15 | -> (A) -> C { 16 | 17 | return { (a: A) -> C in 18 | g(f(a)) 19 | } 20 | } 21 | 22 | public func pipe( 23 | _ f: @escaping (A) -> B, 24 | _ g: @escaping (B) -> C, 25 | _ h: @escaping (C) -> D 26 | ) 27 | -> (A) -> D { 28 | 29 | return { (a: A) -> D in 30 | h(g(f(a))) 31 | } 32 | } 33 | 34 | public func pipe( 35 | _ f: @escaping (A) -> B, 36 | _ g: @escaping (B) -> C, 37 | _ h: @escaping (C) -> D, 38 | _ i: @escaping (D) -> E 39 | ) 40 | -> (A) -> E { 41 | 42 | return { (a: A) -> E in 43 | i(h(g(f(a)))) 44 | } 45 | } 46 | 47 | public func pipe( 48 | _ f: @escaping (A) -> B, 49 | _ g: @escaping (B) -> C, 50 | _ h: @escaping (C) -> D, 51 | _ i: @escaping (D) -> E, 52 | _ j: @escaping (E) -> F 53 | ) 54 | -> (A) -> F { 55 | 56 | return { (a: A) -> F in 57 | j(i(h(g(f(a))))) 58 | } 59 | } 60 | 61 | public func pipe( 62 | _ f: @escaping (A) -> B, 63 | _ g: @escaping (B) -> C, 64 | _ h: @escaping (C) -> D, 65 | _ i: @escaping (D) -> E, 66 | _ j: @escaping (E) -> F, 67 | _ k: @escaping (F) -> G 68 | ) 69 | -> (A) -> G { 70 | 71 | return { (a: A) -> G in 72 | k(j(i(h(g(f(a)))))) 73 | } 74 | } 75 | 76 | /// Forward composition of functions. 77 | /// 78 | /// - Parameters: 79 | /// - f: A function that takes a value in `A` and returns a value in `B`. 80 | /// - a: An argument in `A`. 81 | /// - g: A function that takes a value in `B` and returns a value in `C`. 82 | /// - b: An argument in `B`. 83 | /// - Returns: A new function that takes a value in `A` and returns a value in `C`. 84 | /// - Note: This function is commonly seen in operator form as `>>>`. 85 | public func pipe( 86 | _ f: @escaping (_ a: A) throws -> B, 87 | _ g: @escaping (_ b: B) throws -> C 88 | ) 89 | -> (A) throws -> C { 90 | 91 | return { (a: A) throws -> C in 92 | try g(f(a)) 93 | } 94 | } 95 | 96 | public func pipe( 97 | _ f: @escaping (A) throws -> B, 98 | _ g: @escaping (B) throws -> C, 99 | _ h: @escaping (C) throws -> D 100 | ) 101 | -> (A) throws -> D { 102 | 103 | return { (a: A) throws -> D in 104 | try h(g(f(a))) 105 | } 106 | } 107 | 108 | public func pipe( 109 | _ f: @escaping (A) throws -> B, 110 | _ g: @escaping (B) throws -> C, 111 | _ h: @escaping (C) throws -> D, 112 | _ i: @escaping (D) throws -> E 113 | ) 114 | -> (A) throws -> E { 115 | 116 | return { (a: A) throws -> E in 117 | try i(h(g(f(a)))) 118 | } 119 | } 120 | 121 | public func pipe( 122 | _ f: @escaping (A) throws -> B, 123 | _ g: @escaping (B) throws -> C, 124 | _ h: @escaping (C) throws -> D, 125 | _ i: @escaping (D) throws -> E, 126 | _ j: @escaping (E) throws -> F 127 | ) 128 | -> (A) throws -> F { 129 | 130 | return { (a: A) throws -> F in 131 | try j(i(h(g(f(a))))) 132 | } 133 | } 134 | 135 | public func pipe( 136 | _ f: @escaping (A) throws -> B, 137 | _ g: @escaping (B) throws -> C, 138 | _ h: @escaping (C) throws -> D, 139 | _ i: @escaping (D) throws -> E, 140 | _ j: @escaping (E) throws -> F, 141 | _ k: @escaping (F) throws -> G 142 | ) 143 | -> (A) throws -> G { 144 | 145 | return { (a: A) throws -> G in 146 | try k(j(i(h(g(f(a)))))) 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Sources/Overture/Result.swift: -------------------------------------------------------------------------------- 1 | /// Transforms a pair of results into a result of a pair. 2 | /// 3 | /// - Parameters: 4 | /// - result1: A result. 5 | /// - result2: Another result. 6 | /// - Returns: A result of a pair. 7 | public func zip( 8 | _ result1: Result, 9 | _ result2: Result 10 | ) -> Result<(A, B), Error> { 11 | return result1.flatMap { a in result2.map { b in (a, b) } } 12 | } 13 | 14 | /// Transforms a pair of results into a new result. 15 | /// 16 | /// - Parameters: 17 | /// - result1: A result. 18 | /// - result2: Another result. 19 | /// - transform: A transform function. 20 | /// - Returns: A transformed result. 21 | public func zip( 22 | with transform: @escaping (A, B) -> Z, 23 | _ result1: Result, 24 | _ result2: Result 25 | ) -> Result { 26 | return zip(result1, result2).map(transform) 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Overture/Sequence.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Free `map` on sequences for function composition. 3 | /// 4 | /// - Parameter transform: A transform function. 5 | /// - Returns: An array with each sequence element transformed. 6 | public func map( 7 | _ transform: @escaping (S.Element) -> A 8 | ) 9 | -> (S) -> [A] { 10 | 11 | return { $0.map(transform) } 12 | } 13 | 14 | /// Free `map` on sequences for throwing function composition. 15 | /// 16 | /// - Parameter transform: A transform function. 17 | /// - Returns: An array with each sequence element transformed. 18 | public func map( 19 | _ transform: @escaping (S.Element) throws -> A 20 | ) 21 | -> (S) throws -> [A] { 22 | 23 | return { try $0.map(transform) } 24 | } 25 | 26 | /// In-place collection mutation. 27 | /// 28 | /// - Parameter transform: A transform function. 29 | public func mutEach( 30 | _ transform: @escaping (inout C.Element) -> Void 31 | ) 32 | -> (inout C) -> Void { 33 | 34 | return { 35 | for i in $0.indices { 36 | transform(&$0[i]) 37 | } 38 | } 39 | } 40 | 41 | /// Transforms a pair of sequences into a sequence of pairs. 42 | /// 43 | /// - Parameters: 44 | /// - transform: A transform function. 45 | /// - sequence1: A sequence. 46 | /// - sequence2: Another sequence. 47 | /// - Returns: A transformed sequence. 48 | public func zip( 49 | with transform: (A.Element, B.Element) -> Z, 50 | _ sequence1: A, 51 | _ sequence2: B 52 | ) -> [Z] 53 | where A: Sequence, B: Sequence { 54 | return zip(sequence1, sequence2).map(transform) 55 | } 56 | -------------------------------------------------------------------------------- /Sources/Overture/Setters.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Applies a value transformation to an immutable setter function. 3 | /// 4 | /// - Parameters: 5 | /// - setter: An immutable setter function. 6 | /// - f: A value transform function. 7 | /// - Returns: A root transform function. 8 | public func over( 9 | _ setter: (@escaping (A) -> B) -> (S) -> T, 10 | _ f: @escaping (A) -> B 11 | ) 12 | -> (S) -> T { 13 | 14 | return setter(f) 15 | } 16 | 17 | /// Applies a value to an immutable setter function. 18 | /// 19 | /// - Parameters: 20 | /// - setter: An immutable setter function. 21 | /// - value: A new value. 22 | /// - Returns: A root transform function. 23 | public func set( 24 | _ setter: (@escaping (A) -> B) -> (S) -> T, 25 | _ value: B 26 | ) 27 | -> (S) -> T { 28 | 29 | return over(setter) { _ in value } 30 | } 31 | 32 | // MARK: - Mutation 33 | 34 | /// Applies a mutable value transformation to a mutable setter function. 35 | /// 36 | /// - Parameters: 37 | /// - setter: A mutable setter function. 38 | /// - f: A mutable value transform function. 39 | /// - Returns: A mutable root transform function. 40 | public func mver( 41 | _ setter: (@escaping (inout A) -> Void) -> (inout S) -> Void, 42 | _ f: @escaping (inout A) -> Void 43 | ) 44 | -> (inout S) -> Void { 45 | 46 | return setter(f) 47 | } 48 | 49 | /// Applies a mutable value transformation to a reference-mutable setter function. 50 | /// 51 | /// - Parameters: 52 | /// - setter: A reference-mutable setter function. 53 | /// - f: A mutable value transform function. 54 | /// - Returns: A reference-mutable root transform function. 55 | public func mver( 56 | _ setter: (@escaping (inout A) -> Void) -> (S) -> Void, 57 | _ f: @escaping (inout A) -> Void 58 | ) 59 | -> (S) -> Void 60 | where S: AnyObject { 61 | 62 | return setter(f) 63 | } 64 | 65 | /// Applies a reference-mutable value transformation to a reference-mutable setter function. 66 | /// 67 | /// - Parameters: 68 | /// - setter: A reference-mutable setter function. 69 | /// - f: A mutable value transform function. 70 | /// - Returns: A reference-mutable root transform function. 71 | public func mver( 72 | _ setter: (@escaping (A) -> Void) -> (S) -> Void, 73 | _ f: @escaping (A) -> Void 74 | ) 75 | -> (S) -> Void 76 | where S: AnyObject, A: AnyObject { 77 | 78 | return setter(f) 79 | } 80 | 81 | /// Applies a value to a mutable setter function. 82 | /// 83 | /// - Parameters: 84 | /// - setter: An mutable setter function. 85 | /// - value: A new value. 86 | /// - Returns: A mutable root transform function. 87 | public func mut( 88 | _ setter: (@escaping (inout A) -> Void) -> (inout S) -> Void, 89 | _ value: A 90 | ) 91 | -> (inout S) -> Void { 92 | 93 | return mver(setter) { $0 = value } 94 | } 95 | 96 | /// Applies a value to a reference-mutable setter function. 97 | /// 98 | /// - Parameters: 99 | /// - setter: An mutable setter function. 100 | /// - value: A new value. 101 | /// - Returns: A reference-mutable root transform function. 102 | public func mut( 103 | _ setter: (@escaping (inout A) -> Void) -> (S) -> Void, 104 | _ value: A 105 | ) 106 | -> (S) -> Void 107 | where S: AnyObject { 108 | 109 | return mver(setter) { $0 = value } 110 | } 111 | -------------------------------------------------------------------------------- /Sources/Overture/Uncurry.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Uncurries a function. 3 | /// 4 | /// - Parameter function: A function with one argument, that returns another function with one argument. 5 | /// - Returns: An uncurried function. 6 | public func uncurry(_ function: @escaping 7 | (A) 8 | -> (B) 9 | -> C) 10 | -> (A, B) 11 | -> C { 12 | return { (a: A, b: B) -> C in 13 | function(a)(b) 14 | } 15 | } 16 | 17 | /// Uncurries a throwing function. 18 | /// 19 | /// - Parameter function: A throwing function with one argument, that returns another function with one argument. 20 | /// - Returns: An uncurried, final-throwing function. 21 | public func uncurry(_ function: @escaping 22 | (A) 23 | -> (B) throws 24 | -> C) 25 | -> (A, B) throws 26 | -> C { 27 | return { (a: A, b: B) throws -> C in 28 | try function(a)(b) 29 | } 30 | } 31 | 32 | public func uncurry(_ function: @escaping 33 | (A) 34 | -> (B) 35 | -> (C) 36 | -> D) 37 | -> (A, B, C) 38 | -> D { 39 | return { (a: A, b: B, c: C) -> D in 40 | function(a)(b)(c) 41 | } 42 | } 43 | 44 | public func uncurry(_ function: @escaping 45 | (A) 46 | -> (B) 47 | -> (C) throws 48 | -> D) 49 | -> (A, B, C) throws 50 | -> D { 51 | return { (a: A, b: B, c: C) throws -> D in 52 | try function(a)(b)(c) 53 | } 54 | } 55 | 56 | public func uncurry(_ function: @escaping 57 | (A) 58 | -> (B) 59 | -> (C) 60 | -> (D) 61 | -> E) 62 | -> (A, B, C, D) 63 | -> E { 64 | return { (a: A, b: B, c: C, d: D) -> E in 65 | function(a)(b)(c)(d) 66 | } 67 | } 68 | 69 | public func uncurry(_ function: @escaping 70 | (A) 71 | -> (B) 72 | -> (C) 73 | -> (D) throws 74 | -> E) 75 | -> (A, B, C, D) throws 76 | -> E { 77 | return { (a: A, b: B, c: C, d: D) throws -> E in 78 | try function(a)(b)(c)(d) 79 | } 80 | } 81 | 82 | public func uncurry(_ function: @escaping 83 | (A) 84 | -> (B) 85 | -> (C) 86 | -> (D) 87 | -> (E) -> F) 88 | -> (A, B, C, D, E) 89 | -> F { 90 | return { (a: A, b: B, c: C, d: D, e: E) -> F in 91 | function(a)(b)(c)(d)(e) 92 | } 93 | } 94 | 95 | public func uncurry(_ function: @escaping 96 | (A) 97 | -> (B) 98 | -> (C) 99 | -> (D) 100 | -> (E) throws 101 | -> F) 102 | -> (A, B, C, D, E) throws 103 | -> F { 104 | return { (a: A, b: B, c: C, d: D, e: E) throws -> F in 105 | try function(a)(b)(c)(d)(e) 106 | } 107 | } 108 | 109 | public func uncurry(_ function: @escaping 110 | (A) 111 | -> (B) 112 | -> (C) 113 | -> (D) 114 | -> (E) 115 | -> (F) 116 | -> G) 117 | -> (A, B, C, D, E, F) 118 | -> G { 119 | return { (a: A, b: B, c: C, d: D, e: E, f: F) -> G in 120 | function(a)(b)(c)(d)(e)(f) 121 | } 122 | } 123 | 124 | public func uncurry(_ function: @escaping 125 | (A) 126 | -> (B) 127 | -> (C) 128 | -> (D) 129 | -> (E) 130 | -> (F) throws 131 | -> G) 132 | -> (A, B, C, D, E, F) throws 133 | -> G { 134 | return { (a: A, b: B, c: C, d: D, e: E, f: F) throws -> G in 135 | try function(a)(b)(c)(d)(e)(f) 136 | } 137 | } 138 | 139 | public func uncurry(_ function: @escaping 140 | (A) 141 | -> (B) 142 | -> (C) 143 | -> (D) 144 | -> (E) 145 | -> (F) 146 | -> (G) 147 | -> H) 148 | -> (A, B, C, D, E, F, G) 149 | -> H { 150 | return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G) -> H in 151 | function(a)(b)(c)(d)(e)(f)(g) 152 | } 153 | } 154 | 155 | public func uncurry(_ function: @escaping 156 | (A) 157 | -> (B) 158 | -> (C) 159 | -> (D) 160 | -> (E) 161 | -> (F) 162 | -> (G) throws 163 | -> H) 164 | -> (A, B, C, D, E, F, G) throws 165 | -> H { 166 | return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G) throws -> H in 167 | try function(a)(b)(c)(d)(e)(f)(g) 168 | } 169 | } 170 | 171 | public func uncurry(_ function: @escaping 172 | (A) 173 | -> (B) 174 | -> (C) 175 | -> (D) 176 | -> (E) 177 | -> (F) 178 | -> (G) 179 | -> (H) 180 | -> I) 181 | -> (A, B, C, D, E, F, G, H) 182 | -> I { 183 | return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) -> I in 184 | function(a)(b)(c)(d)(e)(f)(g)(h) 185 | } 186 | } 187 | 188 | public func uncurry(_ function: @escaping 189 | (A) 190 | -> (B) 191 | -> (C) 192 | -> (D) 193 | -> (E) 194 | -> (F) 195 | -> (G) 196 | -> (H) throws 197 | -> I) 198 | -> (A, B, C, D, E, F, G, H) throws 199 | -> I { 200 | return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) throws -> I in 201 | try function(a)(b)(c)(d)(e)(f)(g)(h) 202 | } 203 | } 204 | 205 | public func uncurry(_ function: @escaping 206 | (A) 207 | -> (B) 208 | -> (C) 209 | -> (D) 210 | -> (E) 211 | -> (F) 212 | -> (G) 213 | -> (H) 214 | -> (I) 215 | -> J) 216 | -> (A, B, C, D, E, F, G, H, I) 217 | -> J { 218 | return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) -> J in 219 | function(a)(b)(c)(d)(e)(f)(g)(h)(i) 220 | } 221 | } 222 | 223 | public func uncurry(_ function: @escaping 224 | (A) 225 | -> (B) 226 | -> (C) 227 | -> (D) 228 | -> (E) 229 | -> (F) 230 | -> (G) 231 | -> (H) 232 | -> (I) throws 233 | -> J) 234 | -> (A, B, C, D, E, F, G, H, I) throws 235 | -> J { 236 | return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) throws -> J in 237 | try function(a)(b)(c)(d)(e)(f)(g)(h)(i) 238 | } 239 | } 240 | 241 | public func uncurry(_ function: @escaping 242 | (A) 243 | -> (B) 244 | -> (C) 245 | -> (D) 246 | -> (E) 247 | -> (F) 248 | -> (G) 249 | -> (H) 250 | -> (I) 251 | -> (J) 252 | -> K) 253 | -> (A, B, C, D, E, F, G, H, I, J) 254 | -> K { 255 | return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) -> K in 256 | function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j) 257 | } 258 | } 259 | 260 | public func uncurry(_ function: @escaping 261 | (A) 262 | -> (B) 263 | -> (C) 264 | -> (D) 265 | -> (E) 266 | -> (F) 267 | -> (G) 268 | -> (H) 269 | -> (I) 270 | -> (J) throws 271 | -> K) 272 | -> (A, B, C, D, E, F, G, H, I, J) throws 273 | -> K { 274 | return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) throws -> K in 275 | try function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j) 276 | } 277 | } 278 | 279 | public func uncurry(_ function: @escaping 280 | (A) 281 | -> (B) 282 | -> (C) 283 | -> (D) 284 | -> (E) 285 | -> (F) 286 | -> (G) 287 | -> (H) 288 | -> (I) 289 | -> (J) 290 | -> (K) 291 | -> L) 292 | -> (A, B, C, D, E, F, G, H, I, J, K) 293 | -> L { 294 | return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K) -> L in 295 | function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k) 296 | } 297 | } 298 | 299 | public func uncurry(_ function: @escaping 300 | (A) 301 | -> (B) 302 | -> (C) 303 | -> (D) 304 | -> (E) 305 | -> (F) 306 | -> (G) 307 | -> (H) 308 | -> (I) 309 | -> (J) 310 | -> (K) throws 311 | -> L) 312 | -> (A, B, C, D, E, F, G, H, I, J, K) throws 313 | -> L { 314 | return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K) throws -> L in 315 | try function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k) 316 | } 317 | } 318 | 319 | public func uncurry(_ function: @escaping 320 | (A) 321 | -> (B) 322 | -> (C) 323 | -> (D) 324 | -> (E) 325 | -> (F) 326 | -> (G) 327 | -> (H) 328 | -> (I) 329 | -> (J) 330 | -> (K) 331 | -> (L) 332 | -> M) 333 | -> (A, B, C, D, E, F, G, H, I, J, K, L) 334 | -> M { 335 | return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L) -> M in 336 | function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l) 337 | } 338 | } 339 | 340 | public func uncurry(_ function: @escaping 341 | (A) 342 | -> (B) 343 | -> (C) 344 | -> (D) 345 | -> (E) 346 | -> (F) 347 | -> (G) 348 | -> (H) 349 | -> (I) 350 | -> (J) 351 | -> (K) 352 | -> (L) throws 353 | -> M) 354 | -> (A, B, C, D, E, F, G, H, I, J, K, L) throws 355 | -> M { 356 | return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L) throws -> M in 357 | try function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l) 358 | } 359 | } 360 | -------------------------------------------------------------------------------- /Sources/Overture/Update.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Left-to-right, in-place function application. 3 | /// 4 | /// - Parameters: 5 | /// - a: A mutable value. 6 | /// - fs: In-out functions. 7 | /// - Note: This function is commonly seen in operator form as "pipe-forward", `|>`. 8 | public func update(_ a: inout A, _ fs: ((inout A) -> Void)...) { 9 | fs.forEach { f in f(&a) } 10 | } 11 | 12 | /// Left-to-right, in-place throwing function application. 13 | /// 14 | /// - Parameters: 15 | /// - a: A mutable value. 16 | /// - fs: In-out functions. 17 | /// - Note: This function is commonly seen in operator form as "pipe-forward", `|>`. 18 | public func update(_ a: inout A, _ fs: ((inout A) throws -> Void)...) throws { 19 | try fs.forEach { f in try f(&a) } 20 | } 21 | 22 | /// Left-to-right, value-mutable function application. 23 | /// 24 | /// - Parameters: 25 | /// - a: A value. 26 | /// - fs: In-out functions. 27 | /// - Returns: The result of `f` applied to `a`. 28 | /// - Note: This function is commonly seen in operator form as "pipe-forward", `|>`. 29 | public func update(_ a: A, _ fs: ((inout A) -> Void)...) -> A { 30 | var a = a 31 | fs.forEach { f in f(&a) } 32 | return a 33 | } 34 | 35 | /// Left-to-right, value-mutable, throwing function application. 36 | /// 37 | /// - Parameters: 38 | /// - a: A value. 39 | /// - fs: In-out functions. 40 | /// - Returns: The result of `f` applied to `a`. 41 | /// - Note: This function is commonly seen in operator form as "pipe-forward", `|>`. 42 | public func update(_ a: A, _ fs: ((inout A) throws -> Void)...) throws -> A { 43 | var a = a 44 | try fs.forEach { f in try f(&a) } 45 | return a 46 | } 47 | 48 | /// Left-to-right, reference-mutable function application. 49 | /// 50 | /// - Parameters: 51 | /// - a: A mutable value. 52 | /// - f: An function from `A` to `Void`. 53 | /// - Returns: The result of `f` applied to `a`. 54 | /// - Note: This function is commonly seen in operator form as "pipe-forward", `|>`. 55 | @discardableResult 56 | public func updateObject(_ a: A, _ fs: ((A) -> Void)...) -> A { 57 | fs.forEach { f in f(a) } 58 | return a 59 | } 60 | 61 | /// Left-to-right, reference-mutable, throwing function application. 62 | /// 63 | /// - Parameters: 64 | /// - a: A mutable value. 65 | /// - f: An function from `A` to `Void`. 66 | /// - Returns: The result of `f` applied to `a`. 67 | /// - Note: This function is commonly seen in operator form as "pipe-forward", `|>`. 68 | @discardableResult 69 | public func updateObject(_ a: A, _ fs: ((A) throws -> Void)...) throws -> A { 70 | try fs.forEach { f in try f(a) } 71 | return a 72 | } 73 | -------------------------------------------------------------------------------- /Sources/Overture/With.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Left-to-right function application. 3 | /// 4 | /// with(user, getName) // getName(user) 5 | /// 6 | /// - Parameters: 7 | /// - a: A value. 8 | /// - f: A function. 9 | /// - Returns: The result of `f` applied to `a`. 10 | /// - Note: This function is commonly seen in operator form as "pipe-forward", `|>`. 11 | public func with(_ a: A, _ f: (A) throws -> B) rethrows -> B { 12 | return try f(a) 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Overture/ZipOptional.swift: -------------------------------------------------------------------------------- 1 | public func zip( 2 | _ a: A?, 3 | _ b: B?, 4 | _ c: C? 5 | ) -> (A, B, C)? { 6 | return zip(zip(a, b), c).map { ($0.0, $0.1, $1) } 7 | } 8 | 9 | public func zip( 10 | with transform: @escaping (A, B, C) -> Z, 11 | _ a: A?, 12 | _ b: B?, 13 | _ c: C? 14 | ) -> Z? { 15 | return zip(a, b, c).map(transform) 16 | } 17 | 18 | public func zip( 19 | _ a: A?, 20 | _ b: B?, 21 | _ c: C?, 22 | _ d: D? 23 | ) -> (A, B, C, D)? { 24 | return zip(zip(a, b), c, d).map { ($0.0, $0.1, $1, $2) } 25 | } 26 | 27 | public func zip( 28 | with transform: @escaping (A, B, C, D) -> Z, 29 | _ a: A?, 30 | _ b: B?, 31 | _ c: C?, 32 | _ d: D? 33 | ) -> Z? { 34 | return zip(a, b, c, d).map(transform) 35 | } 36 | 37 | public func zip( 38 | _ a: A?, 39 | _ b: B?, 40 | _ c: C?, 41 | _ d: D?, 42 | _ e: E? 43 | ) -> (A, B, C, D, E)? { 44 | return zip(zip(a, b), c, d, e).map { ($0.0, $0.1, $1, $2, $3) } 45 | } 46 | 47 | public func zip( 48 | with transform: @escaping (A, B, C, D, E) -> Z, 49 | _ a: A?, 50 | _ b: B?, 51 | _ c: C?, 52 | _ d: D?, 53 | _ e: E? 54 | ) -> Z? { 55 | return zip(a, b, c, d, e).map(transform) 56 | } 57 | 58 | public func zip( 59 | _ a: A?, 60 | _ b: B?, 61 | _ c: C?, 62 | _ d: D?, 63 | _ e: E?, 64 | _ f: F? 65 | ) -> (A, B, C, D, E, F)? { 66 | return zip(zip(a, b), c, d, e, f).map { ($0.0, $0.1, $1, $2, $3, $4) } 67 | } 68 | 69 | public func zip( 70 | with transform: @escaping (A, B, C, D, E, F) -> Z, 71 | _ a: A?, 72 | _ b: B?, 73 | _ c: C?, 74 | _ d: D?, 75 | _ e: E?, 76 | _ f: F? 77 | ) -> Z? { 78 | return zip(a, b, c, d, e, f).map(transform) 79 | } 80 | 81 | public func zip( 82 | _ a: A?, 83 | _ b: B?, 84 | _ c: C?, 85 | _ d: D?, 86 | _ e: E?, 87 | _ f: F?, 88 | _ g: G? 89 | ) -> (A, B, C, D, E, F, G)? { 90 | return zip(zip(a, b), c, d, e, f, g).map { ($0.0, $0.1, $1, $2, $3, $4, $5) } 91 | } 92 | 93 | public func zip( 94 | with transform: @escaping (A, B, C, D, E, F, G) -> Z, 95 | _ a: A?, 96 | _ b: B?, 97 | _ c: C?, 98 | _ d: D?, 99 | _ e: E?, 100 | _ f: F?, 101 | _ g: G? 102 | ) -> Z? { 103 | return zip(a, b, c, d, e, f, g).map(transform) 104 | } 105 | 106 | public func zip( 107 | _ a: A?, 108 | _ b: B?, 109 | _ c: C?, 110 | _ d: D?, 111 | _ e: E?, 112 | _ f: F?, 113 | _ g: G?, 114 | _ h: H? 115 | ) -> (A, B, C, D, E, F, G, H)? { 116 | return zip(zip(a, b), c, d, e, f, g, h).map { ($0.0, $0.1, $1, $2, $3, $4, $5, $6) } 117 | } 118 | 119 | public func zip( 120 | with transform: @escaping (A, B, C, D, E, F, G, H) -> Z, 121 | _ a: A?, 122 | _ b: B?, 123 | _ c: C?, 124 | _ d: D?, 125 | _ e: E?, 126 | _ f: F?, 127 | _ g: G?, 128 | _ h: H? 129 | ) -> Z? { 130 | return zip(a, b, c, d, e, f, g, h).map(transform) 131 | } 132 | 133 | public func zip( 134 | _ a: A?, 135 | _ b: B?, 136 | _ c: C?, 137 | _ d: D?, 138 | _ e: E?, 139 | _ f: F?, 140 | _ g: G?, 141 | _ h: H?, 142 | _ i: I? 143 | ) -> (A, B, C, D, E, F, G, H, I)? { 144 | return zip(zip(a, b), c, d, e, f, g, h, i).map { ($0.0, $0.1, $1, $2, $3, $4, $5, $6, $7) } 145 | } 146 | 147 | public func zip( 148 | with transform: @escaping (A, B, C, D, E, F, G, H, I) -> Z, 149 | _ a: A?, 150 | _ b: B?, 151 | _ c: C?, 152 | _ d: D?, 153 | _ e: E?, 154 | _ f: F?, 155 | _ g: G?, 156 | _ h: H?, 157 | _ i: I? 158 | ) -> Z? { 159 | return zip(a, b, c, d, e, f, g, h, i).map(transform) 160 | } 161 | 162 | public func zip( 163 | _ a: A?, 164 | _ b: B?, 165 | _ c: C?, 166 | _ d: D?, 167 | _ e: E?, 168 | _ f: F?, 169 | _ g: G?, 170 | _ h: H?, 171 | _ i: I?, 172 | _ j: J? 173 | ) -> (A, B, C, D, E, F, G, H, I, J)? { 174 | return zip(zip(a, b), c, d, e, f, g, h, i, j).map { ($0.0, $0.1, $1, $2, $3, $4, $5, $6, $7, $8) } 175 | } 176 | 177 | public func zip( 178 | with transform: @escaping (A, B, C, D, E, F, G, H, I, J) -> Z, 179 | _ a: A?, 180 | _ b: B?, 181 | _ c: C?, 182 | _ d: D?, 183 | _ e: E?, 184 | _ f: F?, 185 | _ g: G?, 186 | _ h: H?, 187 | _ i: I?, 188 | _ j: J? 189 | ) -> Z? { 190 | return zip(a, b, c, d, e, f, g, h, i, j).map(transform) 191 | } 192 | -------------------------------------------------------------------------------- /Sources/Overture/ZipResult.swift: -------------------------------------------------------------------------------- 1 | public func zip( 2 | _ a: Result, 3 | _ b: Result, 4 | _ c: Result 5 | ) -> Result<(A, B, C), Error> { 6 | return zip(zip(a, b), c).map { ($0.0, $0.1, $1) } 7 | } 8 | 9 | public func zip( 10 | with f: (A, B, C) -> Z, 11 | _ a: Result, 12 | _ b: Result, 13 | _ c: Result 14 | ) -> Result { 15 | return zip(a, b, c).map(f) 16 | } 17 | 18 | public func zip( 19 | _ a: Result, 20 | _ b: Result, 21 | _ c: Result, 22 | _ d: Result 23 | ) -> Result<(A, B, C, D), Error> { 24 | return zip(zip(a, b), c, d).map { ($0.0, $0.1, $1, $2) } 25 | } 26 | 27 | public func zip( 28 | with transform: (A, B, C, D) -> Z, 29 | _ a: Result, 30 | _ b: Result, 31 | _ c: Result, 32 | _ d: Result 33 | ) -> Result { 34 | return zip(a, b, c, d).map(transform) 35 | } 36 | 37 | public func zip( 38 | _ a: Result, 39 | _ b: Result, 40 | _ c: Result, 41 | _ d: Result, 42 | _ e: Result 43 | ) -> Result<(A, B, C, D, E), Error> { 44 | return zip(zip(a, b), c, d, e).map { ($0.0, $0.1, $1, $2, $3) } 45 | } 46 | 47 | public func zip( 48 | with transform: @escaping (A, B, C, D, E) -> Z, 49 | _ a: Result, 50 | _ b: Result, 51 | _ c: Result, 52 | _ d: Result, 53 | _ e: Result 54 | ) -> Result { 55 | return zip(a, b, c, d, e).map(transform) 56 | } 57 | 58 | public func zip( 59 | _ a: Result, 60 | _ b: Result, 61 | _ c: Result, 62 | _ d: Result, 63 | _ e: Result, 64 | _ f: Result 65 | ) -> Result<(A, B, C, D, E, F), Error> { 66 | return zip(zip(a, b), c, d, e, f).map { ($0.0, $0.1, $1, $2, $3, $4) } 67 | } 68 | 69 | public func zip( 70 | with transform: @escaping (A, B, C, D, E, F) -> Z, 71 | _ a: Result, 72 | _ b: Result, 73 | _ c: Result, 74 | _ d: Result, 75 | _ e: Result, 76 | _ f: Result 77 | ) -> Result { 78 | return zip(a, b, c, d, e, f).map(transform) 79 | } 80 | 81 | public func zip( 82 | _ a: Result, 83 | _ b: Result, 84 | _ c: Result, 85 | _ d: Result, 86 | _ e: Result, 87 | _ f: Result, 88 | _ g: Result 89 | ) -> Result<(A, B, C, D, E, F, G), Error> { 90 | return zip(zip(a, b), c, d, e, f, g).map { ($0.0, $0.1, $1, $2, $3, $4, $5) } 91 | } 92 | 93 | public func zip( 94 | with transform: @escaping (A, B, C, D, E, F, G) -> Z, 95 | _ a: Result, 96 | _ b: Result, 97 | _ c: Result, 98 | _ d: Result, 99 | _ e: Result, 100 | _ f: Result, 101 | _ g: Result 102 | ) -> Result { 103 | return zip(a, b, c, d, e, f, g).map(transform) 104 | } 105 | 106 | public func zip( 107 | _ a: Result, 108 | _ b: Result, 109 | _ c: Result, 110 | _ d: Result, 111 | _ e: Result, 112 | _ f: Result, 113 | _ g: Result, 114 | _ h: Result 115 | ) -> Result<(A, B, C, D, E, F, G, H), Error> { 116 | return zip(zip(a, b), c, d, e, f, g, h).map { ($0.0, $0.1, $1, $2, $3, $4, $5, $6) } 117 | } 118 | 119 | public func zip( 120 | with transform: @escaping (A, B, C, D, E, F, G, H) -> Z, 121 | _ a: Result, 122 | _ b: Result, 123 | _ c: Result, 124 | _ d: Result, 125 | _ e: Result, 126 | _ f: Result, 127 | _ g: Result, 128 | _ h: Result 129 | ) -> Result { 130 | return zip(a, b, c, d, e, f, g, h).map(transform) 131 | } 132 | 133 | public func zip( 134 | _ a: Result, 135 | _ b: Result, 136 | _ c: Result, 137 | _ d: Result, 138 | _ e: Result, 139 | _ f: Result, 140 | _ g: Result, 141 | _ h: Result, 142 | _ i: Result 143 | ) 144 | -> Result<(A, B, C, D, E, F, G, H, I), Error> { 145 | return zip(zip(a, b), c, d, e, f, g, h, i).map { ($0.0, $0.1, $1, $2, $3, $4, $5, $6, $7) } 146 | } 147 | 148 | public func zip( 149 | with transform: @escaping (A, B, C, D, E, F, G, H, I) -> Z, 150 | _ a: Result, 151 | _ b: Result, 152 | _ c: Result, 153 | _ d: Result, 154 | _ e: Result, 155 | _ f: Result, 156 | _ g: Result, 157 | _ h: Result, 158 | _ i: Result 159 | ) -> Result { 160 | return zip(a, b, c, d, e, f, g, h, i).map(transform) 161 | } 162 | 163 | public func zip( 164 | _ a: Result, 165 | _ b: Result, 166 | _ c: Result, 167 | _ d: Result, 168 | _ e: Result, 169 | _ f: Result, 170 | _ g: Result, 171 | _ h: Result, 172 | _ i: Result, 173 | _ j: Result 174 | ) -> Result<(A, B, C, D, E, F, G, H, I, J), Error> { 175 | return zip(zip(a, b), c, d, e, f, g, h, i, j).map { ($0.0, $0.1, $1, $2, $3, $4, $5, $6, $7, $8) } 176 | } 177 | 178 | public func zip( 179 | with transform: @escaping (A, B, C, D, E, F, G, H, I, J) -> Z, 180 | _ a: Result, 181 | _ b: Result, 182 | _ c: Result, 183 | _ d: Result, 184 | _ e: Result, 185 | _ f: Result, 186 | _ g: Result, 187 | _ h: Result, 188 | _ i: Result, 189 | _ j: Result 190 | ) -> Result { 191 | return zip(a, b, c, d, e, f, g, h, i, j).map(transform) 192 | } 193 | -------------------------------------------------------------------------------- /Sources/Overture/ZipSequence.swift: -------------------------------------------------------------------------------- 1 | public func zip( 2 | _ a: A, 3 | _ b: B, 4 | _ c: C 5 | ) -> Zip3Sequence { 6 | return Zip3Sequence(a, b, c) 7 | } 8 | 9 | public func zip( 10 | with transform: (A.Element, B.Element, C.Element) -> Z, 11 | _ a: A, 12 | _ b: B, 13 | _ c: C 14 | ) -> [Z] 15 | where A: Sequence, B: Sequence, C: Sequence { 16 | return zip(a, b, c).map(transform) 17 | } 18 | 19 | public func zip( 20 | _ a: A, 21 | _ b: B, 22 | _ c: C, 23 | _ d: D 24 | ) -> Zip4Sequence { 25 | return Zip4Sequence(a, b, c, d) 26 | } 27 | 28 | public func zip( 29 | with transform: (A.Element, B.Element, C.Element, D.Element) -> Z, 30 | _ a: A, 31 | _ b: B, 32 | _ c: C, 33 | _ d: D 34 | ) -> [Z] 35 | where A: Sequence, B: Sequence, C: Sequence, D: Sequence { 36 | return zip(a, b, c, d).map(transform) 37 | } 38 | 39 | public func zip( 40 | _ a: A, 41 | _ b: B, 42 | _ c: C, 43 | _ d: D, 44 | _ e: E 45 | ) -> Zip5Sequence { 46 | return Zip5Sequence(a, b, c, d, e) 47 | } 48 | 49 | public func zip( 50 | with transform: (A.Element, B.Element, C.Element, D.Element, E.Element) -> Z, 51 | _ a: A, 52 | _ b: B, 53 | _ c: C, 54 | _ d: D, 55 | _ e: E 56 | ) -> [Z] 57 | where A: Sequence, B: Sequence, C: Sequence, D: Sequence, E: Sequence { 58 | return zip(a, b, c, d, e).map(transform) 59 | } 60 | 61 | public func zip( 62 | _ a: A, 63 | _ b: B, 64 | _ c: C, 65 | _ d: D, 66 | _ e: E, 67 | _ f: F 68 | ) -> Zip6Sequence { 69 | return Zip6Sequence(a, b, c, d, e, f) 70 | } 71 | 72 | public func zip( 73 | with transform: (A.Element, B.Element, C.Element, D.Element, E.Element, F.Element) -> Z, 74 | _ a: A, 75 | _ b: B, 76 | _ c: C, 77 | _ d: D, 78 | _ e: E, 79 | _ f: F 80 | ) -> [Z] 81 | where A: Sequence, B: Sequence, C: Sequence, D: Sequence, E: Sequence, F: Sequence { 82 | return zip(a, b, c, d, e, f).map(transform) 83 | } 84 | 85 | public func zip( 86 | _ a: A, 87 | _ b: B, 88 | _ c: C, 89 | _ d: D, 90 | _ e: E, 91 | _ f: F, 92 | _ g: G 93 | ) -> Zip7Sequence { 94 | return Zip7Sequence(a, b, c, d, e, f, g) 95 | } 96 | 97 | public func zip( 98 | with transform: (A.Element, B.Element, C.Element, D.Element, E.Element, F.Element, G.Element) -> Z, 99 | _ a: A, 100 | _ b: B, 101 | _ c: C, 102 | _ d: D, 103 | _ e: E, 104 | _ f: F, 105 | _ g: G 106 | ) -> [Z] 107 | where A: Sequence, B: Sequence, C: Sequence, D: Sequence, E: Sequence, F: Sequence, G: Sequence { 108 | return zip(a, b, c, d, e, f, g).map(transform) 109 | } 110 | 111 | public func zip( 112 | _ a: A, 113 | _ b: B, 114 | _ c: C, 115 | _ d: D, 116 | _ e: E, 117 | _ f: F, 118 | _ g: G, 119 | _ h: H 120 | ) -> Zip8Sequence { 121 | return Zip8Sequence(a, b, c, d, e, f, g, h) 122 | } 123 | 124 | public func zip( 125 | with transform: (A.Element, B.Element, C.Element, D.Element, E.Element, F.Element, G.Element, H.Element) -> Z, 126 | _ a: A, 127 | _ b: B, 128 | _ c: C, 129 | _ d: D, 130 | _ e: E, 131 | _ f: F, 132 | _ g: G, 133 | _ h: H 134 | ) -> [Z] 135 | where A: Sequence, B: Sequence, C: Sequence, D: Sequence, E: Sequence, F: Sequence, G: Sequence, H: Sequence { 136 | return zip(a, b, c, d, e, f, g, h).map(transform) 137 | } 138 | 139 | public func zip( 140 | _ a: A, 141 | _ b: B, 142 | _ c: C, 143 | _ d: D, 144 | _ e: E, 145 | _ f: F, 146 | _ g: G, 147 | _ h: H, 148 | _ i: I 149 | ) -> Zip9Sequence { 150 | return Zip9Sequence(a, b, c, d, e, f, g, h, i) 151 | } 152 | 153 | public func zip( 154 | with transform: (A.Element, B.Element, C.Element, D.Element, E.Element, F.Element, G.Element, H.Element, I.Element) -> Z, 155 | _ a: A, 156 | _ b: B, 157 | _ c: C, 158 | _ d: D, 159 | _ e: E, 160 | _ f: F, 161 | _ g: G, 162 | _ h: H, 163 | _ i: I 164 | ) -> [Z] 165 | where A: Sequence, B: Sequence, C: Sequence, D: Sequence, E: Sequence, F: Sequence, G: Sequence, H: Sequence, I: Sequence { 166 | return zip(a, b, c, d, e, f, g, h, i).map(transform) 167 | } 168 | 169 | public func zip( 170 | _ a: A, 171 | _ b: B, 172 | _ c: C, 173 | _ d: D, 174 | _ e: E, 175 | _ f: F, 176 | _ g: G, 177 | _ h: H, 178 | _ i: I, 179 | _ j: J 180 | ) -> Zip10Sequence { 181 | return Zip10Sequence(a, b, c, d, e, f, g, h, i, j) 182 | } 183 | 184 | public func zip( 185 | with transform: (A.Element, B.Element, C.Element, D.Element, E.Element, F.Element, G.Element, H.Element, I.Element, J.Element) -> Z, 186 | _ a: A, 187 | _ b: B, 188 | _ c: C, 189 | _ d: D, 190 | _ e: E, 191 | _ f: F, 192 | _ g: G, 193 | _ h: H, 194 | _ i: I, 195 | _ j: J 196 | ) -> [Z] 197 | where A: Sequence, B: Sequence, C: Sequence, D: Sequence, E: Sequence, F: Sequence, G: Sequence, H: Sequence, I: Sequence, J: Sequence { 198 | return zip(a, b, c, d, e, f, g, h, i, j).map(transform) 199 | } 200 | 201 | public struct Zip3Sequence< 202 | A: Sequence, 203 | B: Sequence, 204 | C: Sequence 205 | >: Sequence { 206 | internal let _a: A 207 | internal let _b: B 208 | internal let _c: C 209 | 210 | public init(_ a: A, _ b: B, _ c: C) { 211 | _a = a 212 | _b = b 213 | _c = c 214 | } 215 | 216 | public struct Iterator: IteratorProtocol { 217 | internal var _baseStreamA: A.Iterator 218 | internal var _baseStreamB: B.Iterator 219 | internal var _baseStreamC: C.Iterator 220 | internal var _reachedEnd: Bool = false 221 | 222 | internal init( 223 | _ iteratorA: A.Iterator, 224 | _ iteratorB: B.Iterator, 225 | _ iteratorC: C.Iterator 226 | ) { 227 | _baseStreamA = iteratorA 228 | _baseStreamB = iteratorB 229 | _baseStreamC = iteratorC 230 | } 231 | 232 | public typealias Element = ( 233 | A.Element, 234 | B.Element, 235 | C.Element 236 | ) 237 | 238 | public mutating func next() -> Element? { 239 | if _reachedEnd { 240 | return nil 241 | } 242 | 243 | guard 244 | let a = _baseStreamA.next(), 245 | let b = _baseStreamB.next(), 246 | let c = _baseStreamC.next() 247 | else { 248 | _reachedEnd = true 249 | return nil 250 | } 251 | 252 | return (a, b, c) 253 | } 254 | } 255 | 256 | public func makeIterator() -> Iterator { 257 | return Iterator( 258 | _a.makeIterator(), 259 | _b.makeIterator(), 260 | _c.makeIterator() 261 | ) 262 | } 263 | } 264 | 265 | public struct Zip4Sequence< 266 | A: Sequence, 267 | B: Sequence, 268 | C: Sequence, 269 | D: Sequence 270 | >: Sequence { 271 | internal let _a: A 272 | internal let _b: B 273 | internal let _c: C 274 | internal let _d: D 275 | 276 | public init(_ a: A, _ b: B, _ c: C, _ d: D) { 277 | _a = a 278 | _b = b 279 | _c = c 280 | _d = d 281 | } 282 | 283 | public struct Iterator: IteratorProtocol { 284 | internal var _baseStreamA: A.Iterator 285 | internal var _baseStreamB: B.Iterator 286 | internal var _baseStreamC: C.Iterator 287 | internal var _baseStreamD: D.Iterator 288 | internal var _reachedEnd: Bool = false 289 | 290 | internal init( 291 | _ iteratorA: A.Iterator, 292 | _ iteratorB: B.Iterator, 293 | _ iteratorC: C.Iterator, 294 | _ iteratorD: D.Iterator 295 | ) { 296 | _baseStreamA = iteratorA 297 | _baseStreamB = iteratorB 298 | _baseStreamC = iteratorC 299 | _baseStreamD = iteratorD 300 | } 301 | 302 | public typealias Element = ( 303 | A.Element, 304 | B.Element, 305 | C.Element, 306 | D.Element 307 | ) 308 | 309 | public mutating func next() -> Element? { 310 | if _reachedEnd { 311 | return nil 312 | } 313 | 314 | guard 315 | let a = _baseStreamA.next(), 316 | let b = _baseStreamB.next(), 317 | let c = _baseStreamC.next(), 318 | let d = _baseStreamD.next() 319 | else { 320 | _reachedEnd = true 321 | return nil 322 | } 323 | 324 | return (a, b, c, d) 325 | } 326 | } 327 | 328 | public func makeIterator() -> Iterator { 329 | return Iterator( 330 | _a.makeIterator(), 331 | _b.makeIterator(), 332 | _c.makeIterator(), 333 | _d.makeIterator() 334 | ) 335 | } 336 | } 337 | 338 | public struct Zip5Sequence< 339 | A: Sequence, 340 | B: Sequence, 341 | C: Sequence, 342 | D: Sequence, 343 | E: Sequence 344 | >: Sequence { 345 | internal let _a: A 346 | internal let _b: B 347 | internal let _c: C 348 | internal let _d: D 349 | internal let _e: E 350 | 351 | public init(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) { 352 | _a = a 353 | _b = b 354 | _c = c 355 | _d = d 356 | _e = e 357 | } 358 | 359 | public struct Iterator: IteratorProtocol { 360 | internal var _baseStreamA: A.Iterator 361 | internal var _baseStreamB: B.Iterator 362 | internal var _baseStreamC: C.Iterator 363 | internal var _baseStreamD: D.Iterator 364 | internal var _baseStreamE: E.Iterator 365 | internal var _reachedEnd: Bool = false 366 | 367 | internal init( 368 | _ iteratorA: A.Iterator, 369 | _ iteratorB: B.Iterator, 370 | _ iteratorC: C.Iterator, 371 | _ iteratorD: D.Iterator, 372 | _ iteratorE: E.Iterator 373 | ) { 374 | _baseStreamA = iteratorA 375 | _baseStreamB = iteratorB 376 | _baseStreamC = iteratorC 377 | _baseStreamD = iteratorD 378 | _baseStreamE = iteratorE 379 | } 380 | 381 | public typealias Element = ( 382 | A.Element, 383 | B.Element, 384 | C.Element, 385 | D.Element, 386 | E.Element 387 | ) 388 | 389 | public mutating func next() -> Element? { 390 | if _reachedEnd { 391 | return nil 392 | } 393 | 394 | guard 395 | let a = _baseStreamA.next(), 396 | let b = _baseStreamB.next(), 397 | let c = _baseStreamC.next(), 398 | let d = _baseStreamD.next(), 399 | let e = _baseStreamE.next() 400 | else { 401 | _reachedEnd = true 402 | return nil 403 | } 404 | 405 | return (a, b, c, d, e) 406 | } 407 | } 408 | 409 | public func makeIterator() -> Iterator { 410 | return Iterator( 411 | _a.makeIterator(), 412 | _b.makeIterator(), 413 | _c.makeIterator(), 414 | _d.makeIterator(), 415 | _e.makeIterator() 416 | ) 417 | } 418 | } 419 | 420 | public struct Zip6Sequence< 421 | A: Sequence, 422 | B: Sequence, 423 | C: Sequence, 424 | D: Sequence, 425 | E: Sequence, 426 | F: Sequence 427 | >: Sequence { 428 | internal let _a: A 429 | internal let _b: B 430 | internal let _c: C 431 | internal let _d: D 432 | internal let _e: E 433 | internal let _f: F 434 | 435 | public init(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) { 436 | _a = a 437 | _b = b 438 | _c = c 439 | _d = d 440 | _e = e 441 | _f = f 442 | } 443 | 444 | public struct Iterator: IteratorProtocol { 445 | internal var _baseStreamA: A.Iterator 446 | internal var _baseStreamB: B.Iterator 447 | internal var _baseStreamC: C.Iterator 448 | internal var _baseStreamD: D.Iterator 449 | internal var _baseStreamE: E.Iterator 450 | internal var _baseStreamF: F.Iterator 451 | internal var _reachedEnd: Bool = false 452 | 453 | internal init( 454 | _ iteratorA: A.Iterator, 455 | _ iteratorB: B.Iterator, 456 | _ iteratorC: C.Iterator, 457 | _ iteratorD: D.Iterator, 458 | _ iteratorE: E.Iterator, 459 | _ iteratorF: F.Iterator 460 | ) { 461 | _baseStreamA = iteratorA 462 | _baseStreamB = iteratorB 463 | _baseStreamC = iteratorC 464 | _baseStreamD = iteratorD 465 | _baseStreamE = iteratorE 466 | _baseStreamF = iteratorF 467 | } 468 | 469 | public typealias Element = ( 470 | A.Element, 471 | B.Element, 472 | C.Element, 473 | D.Element, 474 | E.Element, 475 | F.Element 476 | ) 477 | 478 | public mutating func next() -> Element? { 479 | if _reachedEnd { 480 | return nil 481 | } 482 | 483 | guard 484 | let a = _baseStreamA.next(), 485 | let b = _baseStreamB.next(), 486 | let c = _baseStreamC.next(), 487 | let d = _baseStreamD.next(), 488 | let e = _baseStreamE.next(), 489 | let f = _baseStreamF.next() 490 | else { 491 | _reachedEnd = true 492 | return nil 493 | } 494 | 495 | return (a, b, c, d, e, f) 496 | } 497 | } 498 | 499 | public func makeIterator() -> Iterator { 500 | return Iterator( 501 | _a.makeIterator(), 502 | _b.makeIterator(), 503 | _c.makeIterator(), 504 | _d.makeIterator(), 505 | _e.makeIterator(), 506 | _f.makeIterator() 507 | ) 508 | } 509 | } 510 | 511 | public struct Zip7Sequence< 512 | A: Sequence, 513 | B: Sequence, 514 | C: Sequence, 515 | D: Sequence, 516 | E: Sequence, 517 | F: Sequence, 518 | G: Sequence 519 | >: Sequence { 520 | internal let _a: A 521 | internal let _b: B 522 | internal let _c: C 523 | internal let _d: D 524 | internal let _e: E 525 | internal let _f: F 526 | internal let _g: G 527 | 528 | public init(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G) { 529 | _a = a 530 | _b = b 531 | _c = c 532 | _d = d 533 | _e = e 534 | _f = f 535 | _g = g 536 | } 537 | 538 | public struct Iterator: IteratorProtocol { 539 | internal var _baseStreamA: A.Iterator 540 | internal var _baseStreamB: B.Iterator 541 | internal var _baseStreamC: C.Iterator 542 | internal var _baseStreamD: D.Iterator 543 | internal var _baseStreamE: E.Iterator 544 | internal var _baseStreamF: F.Iterator 545 | internal var _baseStreamG: G.Iterator 546 | internal var _reachedEnd: Bool = false 547 | 548 | internal init( 549 | _ iteratorA: A.Iterator, 550 | _ iteratorB: B.Iterator, 551 | _ iteratorC: C.Iterator, 552 | _ iteratorD: D.Iterator, 553 | _ iteratorE: E.Iterator, 554 | _ iteratorF: F.Iterator, 555 | _ iteratorG: G.Iterator 556 | ) { 557 | _baseStreamA = iteratorA 558 | _baseStreamB = iteratorB 559 | _baseStreamC = iteratorC 560 | _baseStreamD = iteratorD 561 | _baseStreamE = iteratorE 562 | _baseStreamF = iteratorF 563 | _baseStreamG = iteratorG 564 | } 565 | 566 | public typealias Element = ( 567 | A.Element, 568 | B.Element, 569 | C.Element, 570 | D.Element, 571 | E.Element, 572 | F.Element, 573 | G.Element 574 | ) 575 | 576 | public mutating func next() -> Element? { 577 | if _reachedEnd { 578 | return nil 579 | } 580 | 581 | guard 582 | let a = _baseStreamA.next(), 583 | let b = _baseStreamB.next(), 584 | let c = _baseStreamC.next(), 585 | let d = _baseStreamD.next(), 586 | let e = _baseStreamE.next(), 587 | let f = _baseStreamF.next(), 588 | let g = _baseStreamG.next() 589 | else { 590 | _reachedEnd = true 591 | return nil 592 | } 593 | 594 | return (a, b, c, d, e, f, g) 595 | } 596 | } 597 | 598 | public func makeIterator() -> Iterator { 599 | return Iterator( 600 | _a.makeIterator(), 601 | _b.makeIterator(), 602 | _c.makeIterator(), 603 | _d.makeIterator(), 604 | _e.makeIterator(), 605 | _f.makeIterator(), 606 | _g.makeIterator() 607 | ) 608 | } 609 | } 610 | 611 | public struct Zip8Sequence< 612 | A: Sequence, 613 | B: Sequence, 614 | C: Sequence, 615 | D: Sequence, 616 | E: Sequence, 617 | F: Sequence, 618 | G: Sequence, 619 | H: Sequence 620 | >: Sequence { 621 | internal let _a: A 622 | internal let _b: B 623 | internal let _c: C 624 | internal let _d: D 625 | internal let _e: E 626 | internal let _f: F 627 | internal let _g: G 628 | internal let _h: H 629 | 630 | public init(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H) { 631 | _a = a 632 | _b = b 633 | _c = c 634 | _d = d 635 | _e = e 636 | _f = f 637 | _g = g 638 | _h = h 639 | } 640 | 641 | public struct Iterator: IteratorProtocol { 642 | internal var _baseStreamA: A.Iterator 643 | internal var _baseStreamB: B.Iterator 644 | internal var _baseStreamC: C.Iterator 645 | internal var _baseStreamD: D.Iterator 646 | internal var _baseStreamE: E.Iterator 647 | internal var _baseStreamF: F.Iterator 648 | internal var _baseStreamG: G.Iterator 649 | internal var _baseStreamH: H.Iterator 650 | internal var _reachedEnd: Bool = false 651 | 652 | internal init( 653 | _ iteratorA: A.Iterator, 654 | _ iteratorB: B.Iterator, 655 | _ iteratorC: C.Iterator, 656 | _ iteratorD: D.Iterator, 657 | _ iteratorE: E.Iterator, 658 | _ iteratorF: F.Iterator, 659 | _ iteratorG: G.Iterator, 660 | _ iteratorH: H.Iterator 661 | ) { 662 | _baseStreamA = iteratorA 663 | _baseStreamB = iteratorB 664 | _baseStreamC = iteratorC 665 | _baseStreamD = iteratorD 666 | _baseStreamE = iteratorE 667 | _baseStreamF = iteratorF 668 | _baseStreamG = iteratorG 669 | _baseStreamH = iteratorH 670 | } 671 | 672 | public typealias Element = ( 673 | A.Element, 674 | B.Element, 675 | C.Element, 676 | D.Element, 677 | E.Element, 678 | F.Element, 679 | G.Element, 680 | H.Element 681 | ) 682 | 683 | public mutating func next() -> Element? { 684 | if _reachedEnd { 685 | return nil 686 | } 687 | 688 | guard 689 | let a = _baseStreamA.next(), 690 | let b = _baseStreamB.next(), 691 | let c = _baseStreamC.next(), 692 | let d = _baseStreamD.next(), 693 | let e = _baseStreamE.next(), 694 | let f = _baseStreamF.next(), 695 | let g = _baseStreamG.next(), 696 | let h = _baseStreamH.next() 697 | else { 698 | _reachedEnd = true 699 | return nil 700 | } 701 | 702 | return (a, b, c, d, e, f, g, h) 703 | } 704 | } 705 | 706 | public func makeIterator() -> Iterator { 707 | return Iterator( 708 | _a.makeIterator(), 709 | _b.makeIterator(), 710 | _c.makeIterator(), 711 | _d.makeIterator(), 712 | _e.makeIterator(), 713 | _f.makeIterator(), 714 | _g.makeIterator(), 715 | _h.makeIterator() 716 | ) 717 | } 718 | } 719 | 720 | public struct Zip9Sequence< 721 | A: Sequence, 722 | B: Sequence, 723 | C: Sequence, 724 | D: Sequence, 725 | E: Sequence, 726 | F: Sequence, 727 | G: Sequence, 728 | H: Sequence, 729 | I: Sequence 730 | >: Sequence { 731 | internal let _a: A 732 | internal let _b: B 733 | internal let _c: C 734 | internal let _d: D 735 | internal let _e: E 736 | internal let _f: F 737 | internal let _g: G 738 | internal let _h: H 739 | internal let _i: I 740 | 741 | public init(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H, _ i: I) { 742 | _a = a 743 | _b = b 744 | _c = c 745 | _d = d 746 | _e = e 747 | _f = f 748 | _g = g 749 | _h = h 750 | _i = i 751 | } 752 | 753 | public struct Iterator: IteratorProtocol { 754 | internal var _baseStreamA: A.Iterator 755 | internal var _baseStreamB: B.Iterator 756 | internal var _baseStreamC: C.Iterator 757 | internal var _baseStreamD: D.Iterator 758 | internal var _baseStreamE: E.Iterator 759 | internal var _baseStreamF: F.Iterator 760 | internal var _baseStreamG: G.Iterator 761 | internal var _baseStreamH: H.Iterator 762 | internal var _baseStreamI: I.Iterator 763 | internal var _reachedEnd: Bool = false 764 | 765 | internal init( 766 | _ iteratorA: A.Iterator, 767 | _ iteratorB: B.Iterator, 768 | _ iteratorC: C.Iterator, 769 | _ iteratorD: D.Iterator, 770 | _ iteratorE: E.Iterator, 771 | _ iteratorF: F.Iterator, 772 | _ iteratorG: G.Iterator, 773 | _ iteratorH: H.Iterator, 774 | _ iteratorI: I.Iterator 775 | ) { 776 | _baseStreamA = iteratorA 777 | _baseStreamB = iteratorB 778 | _baseStreamC = iteratorC 779 | _baseStreamD = iteratorD 780 | _baseStreamE = iteratorE 781 | _baseStreamF = iteratorF 782 | _baseStreamG = iteratorG 783 | _baseStreamH = iteratorH 784 | _baseStreamI = iteratorI 785 | } 786 | 787 | public typealias Element = ( 788 | A.Element, 789 | B.Element, 790 | C.Element, 791 | D.Element, 792 | E.Element, 793 | F.Element, 794 | G.Element, 795 | H.Element, 796 | I.Element 797 | ) 798 | 799 | public mutating func next() -> Element? { 800 | if _reachedEnd { 801 | return nil 802 | } 803 | 804 | guard 805 | let a = _baseStreamA.next(), 806 | let b = _baseStreamB.next(), 807 | let c = _baseStreamC.next(), 808 | let d = _baseStreamD.next(), 809 | let e = _baseStreamE.next(), 810 | let f = _baseStreamF.next(), 811 | let g = _baseStreamG.next(), 812 | let h = _baseStreamH.next(), 813 | let i = _baseStreamI.next() 814 | else { 815 | _reachedEnd = true 816 | return nil 817 | } 818 | 819 | return (a, b, c, d, e, f, g, h, i) 820 | } 821 | } 822 | 823 | public func makeIterator() -> Iterator { 824 | return Iterator( 825 | _a.makeIterator(), 826 | _b.makeIterator(), 827 | _c.makeIterator(), 828 | _d.makeIterator(), 829 | _e.makeIterator(), 830 | _f.makeIterator(), 831 | _g.makeIterator(), 832 | _h.makeIterator(), 833 | _i.makeIterator() 834 | ) 835 | } 836 | } 837 | 838 | public struct Zip10Sequence< 839 | A: Sequence, 840 | B: Sequence, 841 | C: Sequence, 842 | D: Sequence, 843 | E: Sequence, 844 | F: Sequence, 845 | G: Sequence, 846 | H: Sequence, 847 | I: Sequence, 848 | J: Sequence 849 | >: Sequence { 850 | internal let _a: A 851 | internal let _b: B 852 | internal let _c: C 853 | internal let _d: D 854 | internal let _e: E 855 | internal let _f: F 856 | internal let _g: G 857 | internal let _h: H 858 | internal let _i: I 859 | internal let _j: J 860 | 861 | public init(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H, _ i: I, _ j: J) { 862 | _a = a 863 | _b = b 864 | _c = c 865 | _d = d 866 | _e = e 867 | _f = f 868 | _g = g 869 | _h = h 870 | _i = i 871 | _j = j 872 | } 873 | 874 | public struct Iterator: IteratorProtocol { 875 | internal var _baseStreamA: A.Iterator 876 | internal var _baseStreamB: B.Iterator 877 | internal var _baseStreamC: C.Iterator 878 | internal var _baseStreamD: D.Iterator 879 | internal var _baseStreamE: E.Iterator 880 | internal var _baseStreamF: F.Iterator 881 | internal var _baseStreamG: G.Iterator 882 | internal var _baseStreamH: H.Iterator 883 | internal var _baseStreamI: I.Iterator 884 | internal var _baseStreamJ: J.Iterator 885 | internal var _reachedEnd: Bool = false 886 | 887 | internal init( 888 | _ iteratorA: A.Iterator, 889 | _ iteratorB: B.Iterator, 890 | _ iteratorC: C.Iterator, 891 | _ iteratorD: D.Iterator, 892 | _ iteratorE: E.Iterator, 893 | _ iteratorF: F.Iterator, 894 | _ iteratorG: G.Iterator, 895 | _ iteratorH: H.Iterator, 896 | _ iteratorI: I.Iterator, 897 | _ iteratorJ: J.Iterator 898 | ) { 899 | _baseStreamA = iteratorA 900 | _baseStreamB = iteratorB 901 | _baseStreamC = iteratorC 902 | _baseStreamD = iteratorD 903 | _baseStreamE = iteratorE 904 | _baseStreamF = iteratorF 905 | _baseStreamG = iteratorG 906 | _baseStreamH = iteratorH 907 | _baseStreamI = iteratorI 908 | _baseStreamJ = iteratorJ 909 | } 910 | 911 | public typealias Element = ( 912 | A.Element, 913 | B.Element, 914 | C.Element, 915 | D.Element, 916 | E.Element, 917 | F.Element, 918 | G.Element, 919 | H.Element, 920 | I.Element, 921 | J.Element 922 | ) 923 | 924 | public mutating func next() -> Element? { 925 | if _reachedEnd { 926 | return nil 927 | } 928 | 929 | guard 930 | let a = _baseStreamA.next(), 931 | let b = _baseStreamB.next(), 932 | let c = _baseStreamC.next(), 933 | let d = _baseStreamD.next(), 934 | let e = _baseStreamE.next(), 935 | let f = _baseStreamF.next(), 936 | let g = _baseStreamG.next(), 937 | let h = _baseStreamH.next(), 938 | let i = _baseStreamI.next(), 939 | let j = _baseStreamJ.next() 940 | else { 941 | _reachedEnd = true 942 | return nil 943 | } 944 | 945 | return (a, b, c, d, e, f, g, h, i, j) 946 | } 947 | } 948 | 949 | public func makeIterator() -> Iterator { 950 | return Iterator( 951 | _a.makeIterator(), 952 | _b.makeIterator(), 953 | _c.makeIterator(), 954 | _d.makeIterator(), 955 | _e.makeIterator(), 956 | _f.makeIterator(), 957 | _g.makeIterator(), 958 | _h.makeIterator(), 959 | _i.makeIterator(), 960 | _j.makeIterator() 961 | ) 962 | } 963 | } 964 | -------------------------------------------------------------------------------- /Sources/Overture/Zurry.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Calls a function that takes zero arguments. Useful for composing with static, curried methods. 3 | /// 4 | /// - Parameter function: A function taking zero arguments. 5 | /// - Returns: The return value. 6 | public func zurry(_ function: @escaping () throws -> A) rethrows -> A { 7 | return try function() 8 | } 9 | 10 | /// Wraps a value in a function. 11 | /// 12 | /// - Parameter value: A value. 13 | /// - Returns: A wrapper function. 14 | public func unzurry(_ value: @autoclosure @escaping () -> A) -> () -> A { 15 | return value 16 | } 17 | 18 | /// A throwing variant of `unzurry`. 19 | /// 20 | /// - Parameter value: A value. 21 | /// - Returns: A wrapper function. 22 | public func unzurry(_ value: @autoclosure @escaping () throws -> A) -> () throws -> A { 23 | return value 24 | } 25 | -------------------------------------------------------------------------------- /Tests/OvertureTests/ChainTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Overture 3 | 4 | final class ChainTests: XCTestCase { 5 | func testOptionalChain2() { 6 | XCTAssertEqual(.some(9), chain(incr, square)(2)) 7 | XCTAssertNil(chain(incr, fail)(2)) 8 | XCTAssertNil(chain(fail, incr)(2)) 9 | } 10 | 11 | func testThrowingOptionalChain2() { 12 | XCTAssertEqual(.some(9), try chain(nonThrowing(incr), square)(2)) 13 | XCTAssertNil(try chain(nonThrowing(incr), fail)(2)) 14 | XCTAssertNil(try chain(nonThrowing(fail), incr)(2)) 15 | XCTAssertThrowsError(try chain(throwing(incr), square)(2)) 16 | XCTAssertThrowsError(try chain(throwing(incr), fail)(2)) 17 | XCTAssertThrowsError(try chain(throwing(fail), incr)(2)) 18 | XCTAssertThrowsError(try chain(incr, throwing(square))(2)) 19 | XCTAssertThrowsError(try chain(incr, throwing(fail))(2)) 20 | XCTAssertNil(try chain(fail, throwing(incr))(2)) 21 | } 22 | 23 | func testOptionalChain3() { 24 | XCTAssertEqual(.some(16), chain(incr, incr, square)(2)) 25 | XCTAssertNil(chain(incr, incr, fail)(2)) 26 | XCTAssertNil(chain(fail, incr, incr)(2)) 27 | } 28 | 29 | func testThrowingOptionalChain3() { 30 | XCTAssertEqual(.some(16), try chain(nonThrowing(incr), incr, square)(2)) 31 | XCTAssertNil(try chain(nonThrowing(incr), incr, fail)(2)) 32 | XCTAssertNil(try chain(nonThrowing(fail), incr, incr)(2)) 33 | XCTAssertThrowsError(try chain(throwing(incr), incr, square)(2)) 34 | XCTAssertThrowsError(try chain(throwing(incr), incr, fail)(2)) 35 | XCTAssertThrowsError(try chain(throwing(fail), incr, incr)(2)) 36 | XCTAssertThrowsError(try chain(incr, incr, throwing(square))(2)) 37 | XCTAssertThrowsError(try chain(incr, incr, throwing(fail))(2)) 38 | XCTAssertNil(try chain(fail, incr, throwing(incr))(2)) 39 | } 40 | 41 | func testOptionalChain4() { 42 | XCTAssertEqual(.some(25), chain(incr, incr, incr, square)(2)) 43 | XCTAssertNil(chain(incr, incr, incr, fail)(2)) 44 | XCTAssertNil(chain(fail, incr, incr, incr)(2)) 45 | } 46 | 47 | func testThrowingOptionalChain4() { 48 | XCTAssertEqual(.some(25), try chain(nonThrowing(incr), incr, incr, square)(2)) 49 | XCTAssertNil(try chain(nonThrowing(incr), incr, incr, fail)(2)) 50 | XCTAssertNil(try chain(nonThrowing(fail), incr, incr, incr)(2)) 51 | XCTAssertThrowsError(try chain(throwing(incr), incr, incr, square)(2)) 52 | XCTAssertThrowsError(try chain(throwing(incr), incr, incr, fail)(2)) 53 | XCTAssertThrowsError(try chain(throwing(fail), incr, incr, incr)(2)) 54 | XCTAssertThrowsError(try chain(incr, incr, incr, throwing(square))(2)) 55 | XCTAssertThrowsError(try chain(incr, incr, incr, throwing(fail))(2)) 56 | XCTAssertNil(try chain(fail, incr, incr, throwing(incr))(2)) 57 | } 58 | 59 | func testOptionalChain5() { 60 | XCTAssertEqual(.some(36), chain(incr, incr, incr, incr, square)(2)) 61 | XCTAssertNil(chain(incr, incr, incr, incr, fail)(2)) 62 | XCTAssertNil(chain(fail, incr, incr, incr, incr)(2)) 63 | } 64 | 65 | func testThrowingOptionalChain5() { 66 | XCTAssertEqual(.some(36), try chain(nonThrowing(incr), incr, incr, incr, square)(2)) 67 | XCTAssertNil(try chain(nonThrowing(incr), incr, incr, incr, fail)(2)) 68 | XCTAssertNil(try chain(nonThrowing(fail), incr, incr, incr, incr)(2)) 69 | XCTAssertThrowsError(try chain(throwing(incr), incr, incr, incr, square)(2)) 70 | XCTAssertThrowsError(try chain(throwing(incr), incr, incr, incr, fail)(2)) 71 | XCTAssertThrowsError(try chain(throwing(fail), incr, incr, incr, incr)(2)) 72 | XCTAssertThrowsError(try chain(incr, incr, incr, incr, throwing(square))(2)) 73 | XCTAssertThrowsError(try chain(incr, incr, incr, incr, throwing(fail))(2)) 74 | XCTAssertNil(try chain(fail, incr, incr, incr, throwing(incr))(2)) 75 | } 76 | 77 | func testOptionalChain6() { 78 | XCTAssertEqual(.some(49), chain(incr, incr, incr, incr, incr, square)(2)) 79 | XCTAssertNil(chain(incr, incr, incr, incr, incr, fail)(2)) 80 | XCTAssertNil(chain(fail, incr, incr, incr, incr, incr)(2)) 81 | } 82 | 83 | func testThrowingOptionalChain6() { 84 | XCTAssertEqual(.some(49), try chain(nonThrowing(incr), incr, incr, incr, incr, square)(2)) 85 | XCTAssertNil(try chain(nonThrowing(incr), incr, incr, incr, incr, fail)(2)) 86 | XCTAssertNil(try chain(nonThrowing(fail), incr, incr, incr, incr, incr)(2)) 87 | XCTAssertThrowsError(try chain(throwing(incr), incr, incr, incr, incr, square)(2)) 88 | XCTAssertThrowsError(try chain(throwing(incr), incr, incr, incr, incr, fail)(2)) 89 | XCTAssertThrowsError(try chain(throwing(fail), incr, incr, incr, incr, incr)(2)) 90 | XCTAssertThrowsError(try chain(incr, incr, incr, incr, incr, throwing(square))(2)) 91 | XCTAssertThrowsError(try chain(incr, incr, incr, incr, incr, throwing(fail))(2)) 92 | XCTAssertNil(try chain(fail, incr, incr, incr, incr, throwing(incr))(2)) 93 | } 94 | 95 | func testArrayChain2() { 96 | XCTAssertEqual([1, 1, 2, 2], chain(twoPlusOne, two)(1)) 97 | XCTAssertEqual([1, 2, 1, 2], chain(two, twoPlusOne)(1)) 98 | XCTAssertEqual([], chain(two, zero)(1)) 99 | XCTAssertEqual([], chain(zero, two)(1)) 100 | } 101 | 102 | func testThrowingArrayChain2() { 103 | XCTAssertEqual([1, 1, 2, 2], try chain(nonThrowing(twoPlusOne), two)(1)) 104 | XCTAssertEqual([1, 2, 1, 2], try chain(two, nonThrowing(twoPlusOne))(1)) 105 | XCTAssertEqual([], try chain(nonThrowing(two), zero)(1)) 106 | XCTAssertEqual([], try chain(zero, nonThrowing(two))(1)) 107 | XCTAssertThrowsError(try chain(throwing(twoPlusOne), two)(1)) 108 | XCTAssertThrowsError(try chain(two, throwing(twoPlusOne))(1)) 109 | XCTAssertThrowsError(try chain(throwing(two), zero)(1)) 110 | XCTAssertEqual([], try chain(zero, throwing(two))(1)) 111 | } 112 | 113 | func testArrayChain3() { 114 | XCTAssertEqual(Array(repeatElement(1, count: 8)), chain(two, two, two)(1)) 115 | XCTAssertEqual([], chain(two, two, zero)(1)) 116 | XCTAssertEqual([], chain(zero, two, two)(1)) 117 | } 118 | 119 | func testThrowingArrayChain3() { 120 | XCTAssertEqual(Array(repeatElement(1, count: 8)), try chain(nonThrowing(two), two, two)(1)) 121 | XCTAssertEqual([], try chain(nonThrowing(two), two, zero)(1)) 122 | XCTAssertEqual([], try chain(zero, two, nonThrowing(two))(1)) 123 | XCTAssertThrowsError(try chain(throwing(two), two, two)(1)) 124 | XCTAssertThrowsError(try chain(throwing(two), two, zero)(1)) 125 | XCTAssertEqual([], try chain(zero, two, throwing(two))(1)) 126 | } 127 | 128 | func testArrayChain4() { 129 | XCTAssertEqual(Array(repeatElement(1, count: 16)), chain(two, two, two, two)(1)) 130 | XCTAssertEqual([], chain(two, two, two, zero)(1)) 131 | XCTAssertEqual([], chain(zero, two, two, two)(1)) 132 | } 133 | 134 | func testThrowingArrayChain4() { 135 | XCTAssertEqual(Array(repeatElement(1, count: 16)), try chain(nonThrowing(two), two, two, two)(1)) 136 | XCTAssertEqual([], try chain(nonThrowing(two), two, two, zero)(1)) 137 | XCTAssertEqual([], try chain(zero, two, two, nonThrowing(two))(1)) 138 | XCTAssertThrowsError(try chain(throwing(two), two, two, two)(1)) 139 | XCTAssertThrowsError(try chain(throwing(two), two, two, zero)(1)) 140 | XCTAssertEqual([], try chain(zero, two, two, throwing(two))(1)) 141 | } 142 | 143 | func testArrayChain5() { 144 | XCTAssertEqual(Array(repeatElement(1, count: 32)), chain(two, two, two, two, two)(1)) 145 | XCTAssertEqual([], chain(two, two, two, two, zero)(1)) 146 | XCTAssertEqual([], chain(zero, two, two, two, two)(1)) 147 | } 148 | 149 | func testThrowingArrayChain5() { 150 | XCTAssertEqual(Array(repeatElement(1, count: 32)), try chain(nonThrowing(two), two, two, two, two)(1)) 151 | XCTAssertEqual([], try chain(two, nonThrowing(two), two, two, zero)(1)) 152 | XCTAssertEqual([], try chain(zero, two, nonThrowing(two), two, nonThrowing(two))(1)) 153 | XCTAssertThrowsError(try chain(two, two, throwing(two), two, two)(1)) 154 | XCTAssertThrowsError(try chain(two, two, two, throwing(two), zero)(1)) 155 | XCTAssertEqual([], try chain(zero, two, two, two, throwing(two))(1)) 156 | } 157 | 158 | func testArrayChain6() { 159 | XCTAssertEqual(Array(repeatElement(1, count: 64)), chain(two, two, two, two, two, two)(1)) 160 | XCTAssertEqual([], chain(two, two, two, two, two, zero)(1)) 161 | XCTAssertEqual([], chain(zero, two, two, two, two, two)(1)) 162 | } 163 | 164 | func testThrowingArrayChain6() { 165 | XCTAssertEqual(Array(repeatElement(1, count: 64)), try chain(nonThrowing(two), two, two, two, two, two)(1)) 166 | XCTAssertEqual([], try chain(two, two, two, nonThrowing(two), two, zero)(1)) 167 | XCTAssertEqual([], try chain(zero, two, two, two, nonThrowing(two), two)(1)) 168 | XCTAssertThrowsError(try chain(throwing(two), two, two, two, two, two)(1)) 169 | XCTAssertThrowsError(try chain(two, two, two, throwing(two), two, zero)(1)) 170 | XCTAssertEqual([], try chain(zero, two, two, two, throwing(two), two)(1)) 171 | } 172 | } 173 | 174 | private func incr(_ x: Int) -> Int? { 175 | return .some(x + 1) 176 | } 177 | 178 | private func square(_ x: Int) -> Int? { 179 | return .some(x * x) 180 | } 181 | 182 | private func fail(_ x: Int) -> Int? { 183 | return .none 184 | } 185 | 186 | private func two(_ x: Int) -> [Int] { 187 | return [x, x] 188 | } 189 | 190 | private func twoPlusOne(_ x: Int) -> [Int] { 191 | return [x, x + 1] 192 | } 193 | 194 | private func zero(_ x: Int) -> [Int] { 195 | return [] 196 | } 197 | 198 | private struct ExpectedError: Error {} 199 | private func throwing(_: (A) -> B) -> (A) throws -> B { 200 | return { _ in throw ExpectedError() } 201 | } 202 | 203 | private func nonThrowing(_ f: @escaping (A) -> B) -> (A) throws -> B { 204 | return f 205 | } 206 | -------------------------------------------------------------------------------- /Tests/OvertureTests/ComposeTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Overture 3 | 4 | final class ComposeTests: XCTestCase { 5 | func testCompose2() { 6 | XCTAssertEqual("2", compose(String.init, incr)(1)) 7 | } 8 | 9 | func testThrowingCompose2() { 10 | XCTAssertEqual("2", try compose(nonThrowing(String.init), incr)(1)) 11 | XCTAssertThrowsError(try compose(String.init, throwing(incr))(1)) 12 | } 13 | 14 | func testCompose3() { 15 | XCTAssertEqual("3", compose(String.init, incr, incr)(1)) 16 | } 17 | 18 | func testThrowingCompose3() { 19 | XCTAssertEqual("3", try compose(String.init, nonThrowing(incr), incr)(1)) 20 | XCTAssertThrowsError(try compose(String.init, incr, throwing(incr))(1)) 21 | } 22 | 23 | func testCompose4() { 24 | XCTAssertEqual("4", compose(String.init, incr, incr, incr)(1)) 25 | } 26 | 27 | func testThrowingCompose4() { 28 | XCTAssertEqual("4", try compose(String.init, incr, incr, nonThrowing(incr))(1)) 29 | XCTAssertThrowsError(try compose(throwing(String.init), incr, incr, incr)(1)) 30 | } 31 | 32 | func testCompose5() { 33 | XCTAssertEqual("5", compose(String.init, incr, incr, incr, incr)(1)) 34 | } 35 | 36 | func testThrowingCompose5() { 37 | XCTAssertEqual("5", try compose(String.init, incr, incr, nonThrowing(incr), incr)(1)) 38 | XCTAssertThrowsError(try compose(String.init, incr, throwing(incr), incr, incr)(1)) 39 | } 40 | 41 | func testCompose6() { 42 | XCTAssertEqual("6", compose(String.init, incr, incr, incr, incr, incr)(1)) 43 | } 44 | 45 | func testThrowingCompose6() { 46 | XCTAssertEqual("6", try compose(String.init, incr, incr, nonThrowing(incr), incr, incr)(1)) 47 | XCTAssertThrowsError(try compose(String.init, incr, incr, throwing(incr), incr, incr)(1)) 48 | } 49 | } 50 | 51 | private func incr(_ x: Int) -> Int { 52 | return x + 1 53 | } 54 | 55 | private struct ExpectedError: Error {} 56 | private func throwing(_: (A) -> B) -> (A) throws -> B { 57 | return { _ in throw ExpectedError() } 58 | } 59 | 60 | private func nonThrowing(_ f: @escaping (A) -> B) -> (A) throws -> B { 61 | return f 62 | } 63 | -------------------------------------------------------------------------------- /Tests/OvertureTests/ConcatTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Overture 3 | 4 | final class ConcatTests: XCTestCase { 5 | func testConcat() { 6 | func incr(_ x: Int) -> Int { 7 | return x + 1 8 | } 9 | 10 | func square(_ x: Int) -> Int { 11 | return x * x 12 | } 13 | 14 | XCTAssertEqual(82, concat(incr, incr, square, square, incr)(1)) 15 | XCTAssertEqual(82, concat(incr, incr, square, square) { $0 + 1 }(1)) 16 | } 17 | 18 | func testThrowingConcat() { 19 | func incr(_ x: Int) -> Int { 20 | return x + 1 21 | } 22 | 23 | func square(_ x: Int) -> Int { 24 | return x * x 25 | } 26 | 27 | XCTAssertEqual(82, try concat(incr, nonThrowing(incr), square, square, incr)(1)) 28 | XCTAssertEqual(82, try concat(incr, incr, nonThrowing(square), square) { $0 + 1 }(1)) 29 | XCTAssertThrowsError(try concat(throwing(incr), incr, square, square, incr)(1)) 30 | XCTAssertThrowsError(try concat(incr, incr, square, throwing(square)) { $0 + 1 }(1)) 31 | XCTAssertThrowsError(try concat(incr, incr, square, square, and: throwing(incr))(1)) 32 | } 33 | 34 | func testInoutConcat() { 35 | func incr(_ x: inout Int) { 36 | x += 1 37 | } 38 | 39 | func square(_ x: inout Int) { 40 | x *= x 41 | } 42 | 43 | var x = 1 44 | concat(incr, incr, square, square, incr)(&x) 45 | XCTAssertEqual(82, x) 46 | 47 | x = 1 48 | concat(incr, incr, square, square) { (y: inout Int) in y += 1 }(&x) 49 | XCTAssertEqual(82, x) 50 | } 51 | 52 | func testThrowingInoutConcat() throws { 53 | func incr(_ x: inout Int) { 54 | x += 1 55 | } 56 | 57 | func square(_ x: inout Int) { 58 | x *= x 59 | } 60 | 61 | var x = 1 62 | try concat(incr, nonThrowing(incr), square, square, incr)(&x) 63 | XCTAssertEqual(82, x) 64 | 65 | x = 1 66 | try concat(incr, incr, nonThrowing(square), square) { (y: inout Int) in y += 1 }(&x) 67 | XCTAssertEqual(82, x) 68 | 69 | x = 1 70 | XCTAssertThrowsError(try concat(throwing(incr), incr, square, square, incr)(&x)) 71 | XCTAssertEqual(1, x) 72 | 73 | x = 1 74 | XCTAssertThrowsError(try concat(incr, incr, square, throwing(square)) { (y: inout Int) in y += 1 }(&x)) 75 | XCTAssertEqual(9, x) 76 | 77 | x = 1 78 | XCTAssertThrowsError(try concat(incr, incr, square, square, and: throwing(incr))(&x)) 79 | XCTAssertEqual(81, x) 80 | } 81 | } 82 | 83 | private struct ExpectedError: Error {} 84 | private func throwing(_: (A) -> B) -> (A) throws -> B { 85 | return { _ in throw ExpectedError() } 86 | } 87 | 88 | private func throwing(_: (inout A) -> Void) -> (inout A) throws -> Void { 89 | return { _ in throw ExpectedError() } 90 | } 91 | 92 | private func nonThrowing(_ f: @escaping (A) -> B) -> (A) throws -> B { 93 | return f 94 | } 95 | 96 | private func nonThrowing(_ f: @escaping (inout A) -> Void) -> (inout A) throws -> Void { 97 | return f 98 | } 99 | -------------------------------------------------------------------------------- /Tests/OvertureTests/CurryTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Overture 3 | 4 | final class CurryTests: XCTestCase { 5 | func testCurry() { 6 | let add2: (Int, Int) -> Int = { $0 + $1 } 7 | let add3: (Int, Int, Int) -> Int = { $0 + $1 + $2} 8 | let add4: (Int, Int, Int, Int) -> Int = { $0 + $1 + $2 + $3} 9 | let add5: (Int, Int, Int, Int, Int) -> Int = { $0 + $1 + $2 + $3 + $4} 10 | let add6: (Int, Int, Int, Int, Int, Int) -> Int = { $0 + $1 + $2 + $3 + $4 + $5} 11 | let add7: (Int, Int, Int, Int, Int, Int, Int) -> Int = { $0 + $1 + $2 + $3 + $4 + $5 + $6} 12 | let add8: (Int, Int, Int, Int, Int, Int, Int, Int) -> Int = { $0 + $1 + $2 + $3 + $4 + $5 + $6 + $7} 13 | let add9: (Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int = { $0 + $1 + $2 + $3 + $4 + $5 + $6 + $7 + $8} 14 | let add10: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int = { $0 + $1 + $2 + $3 + $4 + $5 + $6 + $7 + $8 + $9} 15 | let add11: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int = { $0 + $1 + $2 + $3 + $4 + $5 + $6 + $7 + $8 + $9 + $10} 16 | let f2 = curry(add2) 17 | let f3 = curry(add3) 18 | let f4 = curry(add4) 19 | let f5 = curry(add5) 20 | let f6 = curry(add6) 21 | let f7 = curry(add7) 22 | let f8 = curry(add8) 23 | let f9 = curry(add9) 24 | let f10 = curry(add10) 25 | let f11 = curry(add11) 26 | XCTAssertEqual(2, f2(1)(1)) 27 | XCTAssertEqual(3, f3(1)(1)(1)) 28 | XCTAssertEqual(4, f4(1)(1)(1)(1)) 29 | XCTAssertEqual(5, f5(1)(1)(1)(1)(1)) 30 | XCTAssertEqual(6, f6(1)(1)(1)(1)(1)(1)) 31 | XCTAssertEqual(7, f7(1)(1)(1)(1)(1)(1)(1)) 32 | XCTAssertEqual(8, f8(1)(1)(1)(1)(1)(1)(1)(1)) 33 | XCTAssertEqual(9, f9(1)(1)(1)(1)(1)(1)(1)(1)(1)) 34 | XCTAssertEqual(10, f10(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)) 35 | XCTAssertEqual(11, f11(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)) 36 | } 37 | 38 | func testThrowing() { 39 | let add1: (Int, Int) throws -> Int = { $0 + $1 } 40 | let add2: (Int, Int, Int) throws -> Int = { $0 + $1 + $2} 41 | let add3: (Int, Int, Int, Int) throws -> Int = { $0 + $1 + $2 + $3 } 42 | let add4: (Int, Int, Int, Int, Int) throws -> Int = { $0 + $1 + $2 + $3 + $4} 43 | let add5: (Int, Int, Int, Int, Int, Int) throws -> Int = { $0 + $1 + $2 + $3 + $4 + $5} 44 | let add6: (Int, Int, Int, Int, Int, Int, Int) throws -> Int = { $0 + $1 + $2 + $3 + $4 + $5 + $6} 45 | let add7: (Int, Int, Int, Int, Int, Int, Int, Int) throws -> Int = { $0 + $1 + $2 + $3 + $4 + $5 + $6 + $7} 46 | let add8: (Int, Int, Int, Int, Int, Int, Int, Int, Int) throws -> Int = { $0 + $1 + $2 + $3 + $4 + $5 + $6 + $7 + $8} 47 | let add9: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) throws -> Int = { $0 + $1 + $2 + $3 + $4 + $5 + $6 + $7 + $8 + $9} 48 | let add10: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) throws -> Int = { $0 + $1 + $2 + $3 + $4 + $5 + $6 + $7 + $8 + $9 + $10} 49 | let add11: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) throws -> Int = { $0 + $1 + $2 + $3 + $4 + $5 + $6 + $7 + $8 + $9 + $10 + $11} 50 | let f1 = curry(add1) 51 | let f2 = curry(add2) 52 | let f3 = curry(add3) 53 | let f4 = curry(add4) 54 | let f5 = curry(add5) 55 | let f6 = curry(add6) 56 | let f7 = curry(add7) 57 | let f8 = curry(add8) 58 | let f9 = curry(add9) 59 | let f10 = curry(add10) 60 | let f11 = curry(add11) 61 | XCTAssertEqual(2, try f1(1)(1)) 62 | XCTAssertEqual(3, try f2(1)(1)(1)) 63 | XCTAssertEqual(4, try f3(1)(1)(1)(1)) 64 | XCTAssertEqual(5, try f4(1)(1)(1)(1)(1)) 65 | XCTAssertEqual(6, try f5(1)(1)(1)(1)(1)(1)) 66 | XCTAssertEqual(7, try f6(1)(1)(1)(1)(1)(1)(1)) 67 | XCTAssertEqual(8, try f7(1)(1)(1)(1)(1)(1)(1)(1)) 68 | XCTAssertEqual(9, try f8(1)(1)(1)(1)(1)(1)(1)(1)(1)) 69 | XCTAssertEqual(10, try f9(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)) 70 | XCTAssertEqual(11, try f10(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)) 71 | XCTAssertEqual(12, try f11(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Tests/OvertureTests/FlipTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Overture 3 | 4 | class FlipTests: XCTestCase { 5 | func testFlip() { 6 | let capitalized = flip(String.capitalized) 7 | 8 | let result = ["hello, world", "and good night"] 9 | .map(capitalized(Locale(identifier: "en"))) 10 | 11 | XCTAssertEqual(result, ["Hello, World", "And Good Night"]) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/OvertureTests/KeyPathTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Overture 3 | 4 | final class KeyPathTests: XCTestCase { 5 | func testGet() { 6 | XCTAssertEqual([1, 2, 3], [".", "..", "..."].map(get(\.count))) 7 | } 8 | 9 | func testProp() { 10 | let f = prop(\CGRect.size.width) 11 | let rect = with(CGRect.zero, f { $0 + 1 }) 12 | XCTAssertEqual(1, rect.width) 13 | } 14 | 15 | func testOver() { 16 | let f = over(\CGRect.size.width) { $0 + 1 } 17 | let rect = with(CGRect.zero, f) 18 | XCTAssertEqual(1, rect.width) 19 | } 20 | 21 | func testSet() { 22 | let rect = with(CGRect.zero, set(\.size.width, 1)) 23 | XCTAssertEqual(1, rect.width) 24 | } 25 | 26 | func testInoutMprop() { 27 | let f = mprop(\CGRect.size.width)({ $0 += 1 }) 28 | let rect = update(CGRect.zero, f) 29 | XCTAssertEqual(1, rect.width) 30 | } 31 | 32 | func testInoutMver() { 33 | let f = mver(\CGRect.size.width) { $0 += 1 } 34 | let rect = update(CGRect.zero, f) 35 | XCTAssertEqual(1, rect.width) 36 | } 37 | 38 | func testInoutMut() { 39 | let f = mut(\CGRect.size.width, 1) 40 | let rect = update(CGRect.zero, f) 41 | XCTAssertEqual(1, rect.width) 42 | } 43 | 44 | func testAnyObjectAnyObjectMprop() { 45 | class Bar { 46 | var bazzed = false 47 | func baz() { self.bazzed = true } 48 | } 49 | class Foo { 50 | var bar: Bar 51 | init(bar: Bar) { 52 | self.bar = bar 53 | } 54 | } 55 | 56 | let f = mprop(\Foo.bar)({ $0.baz() }) 57 | let foo = updateObject(Foo(bar: Bar()), f) 58 | XCTAssertTrue(foo.bar.bazzed) 59 | } 60 | 61 | func testAnyObjectInoutMprop() { 62 | let f = (mprop(\Bar.bazzed)) { $0 = !$0 } 63 | let bar = updateObject(Bar(), f) 64 | XCTAssertEqual(true, bar.bazzed) 65 | } 66 | 67 | func testAnyObjectAnyObjectMver() { 68 | let f = mverObject(\Foo.bar) { $0.baz() } 69 | let foo = updateObject(Foo(bar: Bar()), f) 70 | XCTAssertTrue(foo.bar.bazzed) 71 | } 72 | 73 | func testAnyObjectInoutMver() { 74 | let f = mver(\Bar.bazzed) { $0 = !$0 } 75 | let bar = updateObject(Bar(), f) 76 | XCTAssertEqual(true, bar.bazzed) 77 | } 78 | 79 | func testAnyObjectMut() { 80 | let f = mut(\Bar.bazzed, true) 81 | let bar = updateObject(Bar(), f) 82 | XCTAssertEqual(true, bar.bazzed) 83 | } 84 | } 85 | 86 | class Bar { 87 | var bazzed = false 88 | func baz() { self.bazzed = true } 89 | } 90 | class Foo { 91 | var bar: Bar 92 | init(bar: Bar) { 93 | self.bar = bar 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Tests/OvertureTests/PipeTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Overture 3 | 4 | final class PipeTests: XCTestCase { 5 | func testPipe2() { 6 | XCTAssertEqual("2", pipe(incr, String.init)(1)) 7 | } 8 | 9 | func testThrowingPipe2() { 10 | XCTAssertEqual("2", try pipe(nonThrowing(incr), String.init)(1)) 11 | XCTAssertThrowsError(try pipe(throwing(incr), String.init)(1)) 12 | } 13 | 14 | func testPipe3() { 15 | XCTAssertEqual("3", pipe(incr, incr, String.init)(1)) 16 | } 17 | 18 | func testThrowingPipe3() { 19 | XCTAssertEqual("3", try pipe(incr, nonThrowing(incr), String.init)(1)) 20 | XCTAssertThrowsError(try pipe(throwing(incr), incr, String.init)(1)) 21 | } 22 | 23 | func testPipe4() { 24 | XCTAssertEqual("4", pipe(incr, incr, incr, String.init)(1)) 25 | } 26 | 27 | func testThrowingPipe4() { 28 | XCTAssertEqual("4", try pipe(incr, incr, nonThrowing(incr), String.init)(1)) 29 | XCTAssertThrowsError(try pipe(incr, incr, throwing(incr), String.init)(1)) 30 | } 31 | 32 | func testPipe5() { 33 | XCTAssertEqual("5", pipe(incr, incr, incr, incr, String.init)(1)) 34 | } 35 | 36 | func testThrowingPipe5() { 37 | XCTAssertEqual("5", try pipe(incr, incr, incr, incr, nonThrowing(String.init))(1)) 38 | XCTAssertThrowsError(try pipe(incr, throwing(incr), incr, incr, String.init)(1)) 39 | } 40 | 41 | func testPipe6() { 42 | XCTAssertEqual("6", pipe(incr, incr, incr, incr, incr, String.init)(1)) 43 | } 44 | 45 | func testThrowingPipe6() { 46 | XCTAssertEqual("6", try pipe(incr, nonThrowing(incr), incr, incr, incr, String.init)(1)) 47 | XCTAssertThrowsError(try pipe(incr, incr, incr, incr, incr, throwing(String.init))(1)) 48 | } 49 | } 50 | 51 | private func incr(_ x: Int) -> Int { 52 | return x + 1 53 | } 54 | 55 | private struct ExpectedError: Error {} 56 | private func throwing(_: (A) -> B) -> (A) throws -> B { 57 | return { _ in throw ExpectedError() } 58 | } 59 | 60 | private func nonThrowing(_ f: @escaping (A) -> B) -> (A) throws -> B { 61 | return f 62 | } 63 | -------------------------------------------------------------------------------- /Tests/OvertureTests/SettersTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Overture 3 | 4 | final class SettersTests: XCTestCase { 5 | func testOver() { 6 | let f = over(prop(\CGRect.size.width)) { $0 + 1 } 7 | let rect = with(CGRect.zero, f) 8 | XCTAssertEqual(1, rect.width) 9 | 10 | let g = over(prop(\Bar.bazzed)) { !$0 } 11 | let bar = with(Bar(), g) 12 | XCTAssertEqual(true, bar.bazzed) 13 | } 14 | 15 | func testSet() { 16 | let f = set(prop(\CGRect.size.width), 1) 17 | let rect = with(CGRect.zero, f) 18 | XCTAssertEqual(1, rect.width) 19 | 20 | let g = set(prop(\Bar.bazzed), true) 21 | let bar = with(Bar(), g) 22 | XCTAssertEqual(true, bar.bazzed) 23 | } 24 | 25 | func testInoutMver() { 26 | let f = mver(mprop(\CGRect.size.width)) { $0 += 1 } 27 | let rect = update(CGRect.zero, f) 28 | XCTAssertEqual(1, rect.width) 29 | } 30 | 31 | func testAnyObjectInoutMver() { 32 | let g = mver(mprop(\Bar.bazzed)) { $0 = !$0 } 33 | let bar = updateObject(Bar(), g) 34 | XCTAssertEqual(true, bar.bazzed) 35 | } 36 | 37 | func testAnyObjectAnyObjectMver() { 38 | class Bar { 39 | var bazzed = false 40 | func baz() { self.bazzed = true } 41 | } 42 | class Foo { 43 | var bar: Bar 44 | init(bar: Bar) { 45 | self.bar = bar 46 | } 47 | } 48 | 49 | let f = mver(mprop(\Foo.bar)) { $0.baz() } 50 | let foo = updateObject(Foo(bar: Bar()), f) 51 | XCTAssertTrue(foo.bar.bazzed) 52 | } 53 | 54 | func testInoutMut() { 55 | let f = mut(mprop(\CGRect.size.width), 1) 56 | let rect = update(CGRect.zero, f) 57 | XCTAssertEqual(1, rect.width) 58 | } 59 | 60 | func testAnyObjectMut() { 61 | let g = mut(mprop(\Bar.bazzed), true) 62 | let bar = updateObject(Bar(), g) 63 | XCTAssertEqual(true, bar.bazzed) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Tests/OvertureTests/UncurryTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Overture 3 | 4 | final class UncurryTests: XCTestCase { 5 | func testUncurry() { 6 | let add: (Int) -> (Int) -> Int = { val1 in { val2 in val1 + val2 } } 7 | let f = uncurry(add) 8 | XCTAssertEqual(3, f(1, 2)) 9 | } 10 | 11 | func testThrowing() { 12 | let add: (Int) -> (Int) throws -> Int = { val1 in { val2 in val1 + val2 } } 13 | let f = uncurry(add) 14 | XCTAssertEqual(3, try f(1, 2)) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/OvertureTests/WithTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Overture 3 | 4 | final class WithTests: XCTestCase { 5 | func testWith() { 6 | func incr(_ x: Int) -> Int { 7 | return x + 1 8 | } 9 | 10 | XCTAssertEqual(2, with(1, incr)) 11 | XCTAssertEqual(2, try with(1, nonThrowing(incr))) 12 | XCTAssertThrowsError(try with(1, throwing(incr))) 13 | } 14 | 15 | func testInPlaceWith() throws { 16 | func incr(_ x: inout Int) { 17 | x += 1 18 | } 19 | 20 | var x = 1 21 | update(&x, incr) 22 | XCTAssertEqual(2, x) 23 | 24 | x = 1 25 | try update(&x, nonThrowing(incr)) 26 | XCTAssertEqual(2, x) 27 | 28 | x = 1 29 | XCTAssertThrowsError(try update(&x, throwing(incr))) 30 | } 31 | 32 | func testValueCopyableWith() { 33 | func incr(_ x: inout Int) { 34 | x += 1 35 | } 36 | 37 | XCTAssertEqual(2, update(1, incr)) 38 | XCTAssertEqual(2, try? update(1, nonThrowing(incr))) 39 | XCTAssertThrowsError(try update(1, throwing(incr))) 40 | } 41 | 42 | func testReferenceMutableWith() throws { 43 | func currencyStyle(_ fmt: NumberFormatter) { 44 | fmt.numberStyle = .currency 45 | } 46 | 47 | XCTAssertEqual( 48 | .currency, 49 | updateObject(NumberFormatter(), currencyStyle).numberStyle 50 | ) 51 | 52 | XCTAssertEqual( 53 | .currency, 54 | try updateObject(NumberFormatter(), nonThrowing(currencyStyle)).numberStyle 55 | ) 56 | 57 | XCTAssertThrowsError( 58 | try updateObject(NumberFormatter(), throwing(currencyStyle)).numberStyle 59 | ) 60 | } 61 | 62 | func testAmbiguity() { 63 | _ = update(Bar()) { 64 | $0.baz() 65 | } 66 | _ = updateObject(Bar()) { 67 | $0.baz() 68 | } 69 | } 70 | } 71 | 72 | private struct ExpectedError: Error {} 73 | private func throwing(_: (A) -> B) -> (A) throws -> B { 74 | return { _ in throw ExpectedError() } 75 | } 76 | 77 | private func throwing(_: (inout A) -> Void) -> (inout A) throws -> Void { 78 | return { _ in throw ExpectedError() } 79 | } 80 | 81 | private func throwing(_: (A) -> Void) -> (A) throws -> Void { 82 | return { _ in throw ExpectedError() } 83 | } 84 | 85 | private func nonThrowing(_ f: @escaping (A) -> B) -> (A) throws -> B { 86 | return f 87 | } 88 | 89 | private func nonThrowing(_ f: @escaping (inout A) -> Void) -> (inout A) throws -> Void { 90 | return f 91 | } 92 | 93 | private func nonThrowing(_ f: @escaping (A) -> Void) -> (A) throws -> Void { 94 | return f 95 | } 96 | -------------------------------------------------------------------------------- /Tests/OvertureTests/ZipTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Overture 3 | 4 | final class ZipTests: XCTestCase { 5 | func testZipOptional() { 6 | guard 7 | let (a, b, c, d, e, f, g, h, i, j) = zip( 8 | Int?.some(1), 9 | Int?.some(2), 10 | Int?.some(3), 11 | Int?.some(4), 12 | Int?.some(5), 13 | Int?.some(6), 14 | Int?.some(7), 15 | Int?.some(8), 16 | Int?.some(9), 17 | Int?.some(10) 18 | ) 19 | else { return XCTFail() } 20 | 21 | XCTAssertEqual(1, a) 22 | XCTAssertEqual(2, b) 23 | XCTAssertEqual(3, c) 24 | XCTAssertEqual(4, d) 25 | XCTAssertEqual(5, e) 26 | XCTAssertEqual(6, f) 27 | XCTAssertEqual(7, g) 28 | XCTAssertEqual(8, h) 29 | XCTAssertEqual(9, i) 30 | XCTAssertEqual(10, j) 31 | } 32 | 33 | func testZipResult() { 34 | let result = zip( 35 | Result.success(1), 36 | Result.success(2), 37 | Result.success(3), 38 | Result.success(4), 39 | Result.success(5), 40 | Result.success(6), 41 | Result.success(7), 42 | Result.success(8), 43 | Result.success(9), 44 | Result.success(10) 45 | ) 46 | guard 47 | let (a, b, c, d, e, f, g, h, i, j) = try? result.get() 48 | else { return XCTFail() } 49 | 50 | XCTAssertEqual(1, a) 51 | XCTAssertEqual(2, b) 52 | XCTAssertEqual(3, c) 53 | XCTAssertEqual(4, d) 54 | XCTAssertEqual(5, e) 55 | XCTAssertEqual(6, f) 56 | XCTAssertEqual(7, g) 57 | XCTAssertEqual(8, h) 58 | XCTAssertEqual(9, i) 59 | XCTAssertEqual(10, j) 60 | } 61 | 62 | func testZipSequence() { 63 | let zipped = zip( 64 | [1, 2], 65 | [3, 4], 66 | [5, 6], 67 | [7, 8], 68 | [9, 10], 69 | [11, 12], 70 | [13, 14], 71 | [15, 16], 72 | [17, 18], 73 | [19, 20] 74 | ) 75 | let array = Array(zipped) 76 | let fst = array[0] 77 | XCTAssertEqual(1, fst.0) 78 | XCTAssertEqual(3, fst.1) 79 | XCTAssertEqual(5, fst.2) 80 | XCTAssertEqual(7, fst.3) 81 | XCTAssertEqual(9, fst.4) 82 | XCTAssertEqual(11, fst.5) 83 | XCTAssertEqual(13, fst.6) 84 | XCTAssertEqual(15, fst.7) 85 | XCTAssertEqual(17, fst.8) 86 | XCTAssertEqual(19, fst.9) 87 | let snd = array[1] 88 | XCTAssertEqual(2, snd.0) 89 | XCTAssertEqual(4, snd.1) 90 | XCTAssertEqual(6, snd.2) 91 | XCTAssertEqual(8, snd.3) 92 | XCTAssertEqual(10, snd.4) 93 | XCTAssertEqual(12, snd.5) 94 | XCTAssertEqual(14, snd.6) 95 | XCTAssertEqual(16, snd.7) 96 | XCTAssertEqual(18, snd.8) 97 | XCTAssertEqual(20, snd.9) 98 | } 99 | 100 | func testZip2WithSequence() { 101 | struct ZipInit { 102 | let a: Int 103 | let b: Int 104 | 105 | init( 106 | _ a: Int, 107 | _ b: Int 108 | ) { 109 | self.a = a 110 | self.b = b 111 | } 112 | } 113 | let zipped = zip( 114 | with: ZipInit.init, 115 | [1, 2], 116 | [3, 4] 117 | ) 118 | let array = Array(zipped) 119 | let fst = array[0] 120 | XCTAssertEqual(1, fst.a) 121 | XCTAssertEqual(3, fst.b) 122 | let snd = array[1] 123 | XCTAssertEqual(2, snd.a) 124 | XCTAssertEqual(4, snd.b) 125 | } 126 | 127 | func testZip3WithSequence() { 128 | struct ZipInit { 129 | let a: Int 130 | let b: Int 131 | let c: Int 132 | 133 | init( 134 | _ a: Int, 135 | _ b: Int, 136 | _ c: Int 137 | ) { 138 | self.a = a 139 | self.b = b 140 | self.c = c 141 | } 142 | } 143 | let zipped = zip( 144 | with: ZipInit.init, 145 | [1, 2], 146 | [3, 4], 147 | [5, 6] 148 | ) 149 | let array = Array(zipped) 150 | let fst = array[0] 151 | XCTAssertEqual(1, fst.a) 152 | XCTAssertEqual(3, fst.b) 153 | XCTAssertEqual(5, fst.c) 154 | let snd = array[1] 155 | XCTAssertEqual(2, snd.a) 156 | XCTAssertEqual(4, snd.b) 157 | XCTAssertEqual(6, snd.c) 158 | } 159 | 160 | func testZip4WithSequence() { 161 | struct ZipInit { 162 | let a: Int 163 | let b: Int 164 | let c: Int 165 | let d: Int 166 | 167 | init( 168 | _ a: Int, 169 | _ b: Int, 170 | _ c: Int, 171 | _ d: Int 172 | ) { 173 | self.a = a 174 | self.b = b 175 | self.c = c 176 | self.d = d 177 | } 178 | } 179 | let zipped = zip( 180 | with: ZipInit.init, 181 | [1, 2], 182 | [3, 4], 183 | [5, 6], 184 | [7, 8] 185 | ) 186 | let array = Array(zipped) 187 | let fst = array[0] 188 | XCTAssertEqual(1, fst.a) 189 | XCTAssertEqual(3, fst.b) 190 | XCTAssertEqual(5, fst.c) 191 | XCTAssertEqual(7, fst.d) 192 | let snd = array[1] 193 | XCTAssertEqual(2, snd.a) 194 | XCTAssertEqual(4, snd.b) 195 | XCTAssertEqual(6, snd.c) 196 | XCTAssertEqual(8, snd.d) 197 | } 198 | 199 | func testZip5WithSequence() { 200 | struct ZipInit { 201 | let a: Int 202 | let b: Int 203 | let c: Int 204 | let d: Int 205 | let e: Int 206 | 207 | init( 208 | _ a: Int, 209 | _ b: Int, 210 | _ c: Int, 211 | _ d: Int, 212 | _ e: Int 213 | ) { 214 | self.a = a 215 | self.b = b 216 | self.c = c 217 | self.d = d 218 | self.e = e 219 | } 220 | } 221 | let zipped = zip( 222 | with: ZipInit.init, 223 | [1, 2], 224 | [3, 4], 225 | [5, 6], 226 | [7, 8], 227 | [9, 10] 228 | ) 229 | let array = Array(zipped) 230 | let fst = array[0] 231 | XCTAssertEqual(1, fst.a) 232 | XCTAssertEqual(3, fst.b) 233 | XCTAssertEqual(5, fst.c) 234 | XCTAssertEqual(7, fst.d) 235 | XCTAssertEqual(9, fst.e) 236 | let snd = array[1] 237 | XCTAssertEqual(2, snd.a) 238 | XCTAssertEqual(4, snd.b) 239 | XCTAssertEqual(6, snd.c) 240 | XCTAssertEqual(8, snd.d) 241 | XCTAssertEqual(10, snd.e) 242 | } 243 | 244 | func testZip6WithSequence() { 245 | struct ZipInit { 246 | let a: Int 247 | let b: Int 248 | let c: Int 249 | let d: Int 250 | let e: Int 251 | let f: Int 252 | 253 | init( 254 | _ a: Int, 255 | _ b: Int, 256 | _ c: Int, 257 | _ d: Int, 258 | _ e: Int, 259 | _ f: Int 260 | ) { 261 | self.a = a 262 | self.b = b 263 | self.c = c 264 | self.d = d 265 | self.e = e 266 | self.f = f 267 | } 268 | } 269 | let zipped = zip( 270 | with: ZipInit.init, 271 | [1, 2], 272 | [3, 4], 273 | [5, 6], 274 | [7, 8], 275 | [9, 10], 276 | [11, 12] 277 | ) 278 | let array = Array(zipped) 279 | let fst = array[0] 280 | XCTAssertEqual(1, fst.a) 281 | XCTAssertEqual(3, fst.b) 282 | XCTAssertEqual(5, fst.c) 283 | XCTAssertEqual(7, fst.d) 284 | XCTAssertEqual(9, fst.e) 285 | XCTAssertEqual(11, fst.f) 286 | let snd = array[1] 287 | XCTAssertEqual(2, snd.a) 288 | XCTAssertEqual(4, snd.b) 289 | XCTAssertEqual(6, snd.c) 290 | XCTAssertEqual(8, snd.d) 291 | XCTAssertEqual(10, snd.e) 292 | XCTAssertEqual(12, snd.f) 293 | } 294 | 295 | func testZip7WithSequence() { 296 | struct ZipInit { 297 | let a: Int 298 | let b: Int 299 | let c: Int 300 | let d: Int 301 | let e: Int 302 | let f: Int 303 | let g: Int 304 | 305 | init( 306 | _ a: Int, 307 | _ b: Int, 308 | _ c: Int, 309 | _ d: Int, 310 | _ e: Int, 311 | _ f: Int, 312 | _ g: Int 313 | ) { 314 | self.a = a 315 | self.b = b 316 | self.c = c 317 | self.d = d 318 | self.e = e 319 | self.f = f 320 | self.g = g 321 | } 322 | } 323 | let zipped = zip( 324 | with: ZipInit.init, 325 | [1, 2], 326 | [3, 4], 327 | [5, 6], 328 | [7, 8], 329 | [9, 10], 330 | [11, 12], 331 | [13, 14] 332 | ) 333 | let array = Array(zipped) 334 | let fst = array[0] 335 | XCTAssertEqual(1, fst.a) 336 | XCTAssertEqual(3, fst.b) 337 | XCTAssertEqual(5, fst.c) 338 | XCTAssertEqual(7, fst.d) 339 | XCTAssertEqual(9, fst.e) 340 | XCTAssertEqual(11, fst.f) 341 | XCTAssertEqual(13, fst.g) 342 | let snd = array[1] 343 | XCTAssertEqual(2, snd.a) 344 | XCTAssertEqual(4, snd.b) 345 | XCTAssertEqual(6, snd.c) 346 | XCTAssertEqual(8, snd.d) 347 | XCTAssertEqual(10, snd.e) 348 | XCTAssertEqual(12, snd.f) 349 | XCTAssertEqual(14, snd.g) 350 | } 351 | 352 | func testZip8WithSequence() { 353 | struct ZipInit { 354 | let a: Int 355 | let b: Int 356 | let c: Int 357 | let d: Int 358 | let e: Int 359 | let f: Int 360 | let g: Int 361 | let h: Int 362 | 363 | init( 364 | _ a: Int, 365 | _ b: Int, 366 | _ c: Int, 367 | _ d: Int, 368 | _ e: Int, 369 | _ f: Int, 370 | _ g: Int, 371 | _ h: Int 372 | ) { 373 | self.a = a 374 | self.b = b 375 | self.c = c 376 | self.d = d 377 | self.e = e 378 | self.f = f 379 | self.g = g 380 | self.h = h 381 | } 382 | } 383 | let zipped = zip( 384 | with: ZipInit.init, 385 | [1, 2], 386 | [3, 4], 387 | [5, 6], 388 | [7, 8], 389 | [9, 10], 390 | [11, 12], 391 | [13, 14], 392 | [15, 16] 393 | ) 394 | let array = Array(zipped) 395 | let fst = array[0] 396 | XCTAssertEqual(1, fst.a) 397 | XCTAssertEqual(3, fst.b) 398 | XCTAssertEqual(5, fst.c) 399 | XCTAssertEqual(7, fst.d) 400 | XCTAssertEqual(9, fst.e) 401 | XCTAssertEqual(11, fst.f) 402 | XCTAssertEqual(13, fst.g) 403 | XCTAssertEqual(15, fst.h) 404 | let snd = array[1] 405 | XCTAssertEqual(2, snd.a) 406 | XCTAssertEqual(4, snd.b) 407 | XCTAssertEqual(6, snd.c) 408 | XCTAssertEqual(8, snd.d) 409 | XCTAssertEqual(10, snd.e) 410 | XCTAssertEqual(12, snd.f) 411 | XCTAssertEqual(14, snd.g) 412 | XCTAssertEqual(16, snd.h) 413 | } 414 | 415 | func testZip9WithSequence() { 416 | struct ZipInit { 417 | let a: Int 418 | let b: Int 419 | let c: Int 420 | let d: Int 421 | let e: Int 422 | let f: Int 423 | let g: Int 424 | let h: Int 425 | let i: Int 426 | 427 | init( 428 | _ a: Int, 429 | _ b: Int, 430 | _ c: Int, 431 | _ d: Int, 432 | _ e: Int, 433 | _ f: Int, 434 | _ g: Int, 435 | _ h: Int, 436 | _ i: Int 437 | ) { 438 | self.a = a 439 | self.b = b 440 | self.c = c 441 | self.d = d 442 | self.e = e 443 | self.f = f 444 | self.g = g 445 | self.h = h 446 | self.i = i 447 | } 448 | } 449 | let zipped = zip( 450 | with: ZipInit.init, 451 | [1, 2], 452 | [3, 4], 453 | [5, 6], 454 | [7, 8], 455 | [9, 10], 456 | [11, 12], 457 | [13, 14], 458 | [15, 16], 459 | [17, 18] 460 | ) 461 | let array = Array(zipped) 462 | let fst = array[0] 463 | XCTAssertEqual(1, fst.a) 464 | XCTAssertEqual(3, fst.b) 465 | XCTAssertEqual(5, fst.c) 466 | XCTAssertEqual(7, fst.d) 467 | XCTAssertEqual(9, fst.e) 468 | XCTAssertEqual(11, fst.f) 469 | XCTAssertEqual(13, fst.g) 470 | XCTAssertEqual(15, fst.h) 471 | XCTAssertEqual(17, fst.i) 472 | let snd = array[1] 473 | XCTAssertEqual(2, snd.a) 474 | XCTAssertEqual(4, snd.b) 475 | XCTAssertEqual(6, snd.c) 476 | XCTAssertEqual(8, snd.d) 477 | XCTAssertEqual(10, snd.e) 478 | XCTAssertEqual(12, snd.f) 479 | XCTAssertEqual(14, snd.g) 480 | XCTAssertEqual(16, snd.h) 481 | XCTAssertEqual(18, snd.i) 482 | } 483 | 484 | func testZip10WithSequence() { 485 | struct ZipInit { 486 | let a: Int 487 | let b: Int 488 | let c: Int 489 | let d: Int 490 | let e: Int 491 | let f: Int 492 | let g: Int 493 | let h: Int 494 | let i: Int 495 | let j: Int 496 | 497 | init( 498 | _ a: Int, 499 | _ b: Int, 500 | _ c: Int, 501 | _ d: Int, 502 | _ e: Int, 503 | _ f: Int, 504 | _ g: Int, 505 | _ h: Int, 506 | _ i: Int, 507 | _ j: Int 508 | ) { 509 | self.a = a 510 | self.b = b 511 | self.c = c 512 | self.d = d 513 | self.e = e 514 | self.f = f 515 | self.g = g 516 | self.h = h 517 | self.i = i 518 | self.j = j 519 | } 520 | } 521 | let zipped = zip( 522 | with: ZipInit.init, 523 | [1, 2], 524 | [3, 4], 525 | [5, 6], 526 | [7, 8], 527 | [9, 10], 528 | [11, 12], 529 | [13, 14], 530 | [15, 16], 531 | [17, 18], 532 | [19, 20] 533 | ) 534 | let array = Array(zipped) 535 | let fst = array[0] 536 | XCTAssertEqual(1, fst.a) 537 | XCTAssertEqual(3, fst.b) 538 | XCTAssertEqual(5, fst.c) 539 | XCTAssertEqual(7, fst.d) 540 | XCTAssertEqual(9, fst.e) 541 | XCTAssertEqual(11, fst.f) 542 | XCTAssertEqual(13, fst.g) 543 | XCTAssertEqual(15, fst.h) 544 | XCTAssertEqual(17, fst.i) 545 | XCTAssertEqual(19, fst.j) 546 | let snd = array[1] 547 | XCTAssertEqual(2, snd.a) 548 | XCTAssertEqual(4, snd.b) 549 | XCTAssertEqual(6, snd.c) 550 | XCTAssertEqual(8, snd.d) 551 | XCTAssertEqual(10, snd.e) 552 | XCTAssertEqual(12, snd.f) 553 | XCTAssertEqual(14, snd.g) 554 | XCTAssertEqual(16, snd.h) 555 | XCTAssertEqual(18, snd.i) 556 | XCTAssertEqual(20, snd.j) 557 | } 558 | } 559 | --------------------------------------------------------------------------------