{"id":25317365,"url":"https://github.com/xebia-functional/second-bridge","last_synced_at":"2025-10-28T21:30:43.362Z","repository":{"id":28099409,"uuid":"31597632","full_name":"xebia-functional/second-bridge","owner":"xebia-functional","description":"Second Bridge is a Swift framework for functional programming. Our goal is to make Swift development on par with other functional languages like Scala by adding new data types, functions and operators.","archived":false,"fork":false,"pushed_at":"2016-04-01T23:49:46.000Z","size":2285,"stargazers_count":70,"open_issues_count":12,"forks_count":6,"subscribers_count":59,"default_branch":"master","last_synced_at":"2023-10-21T10:01:18.360Z","etag":null,"topics":["cocoapods","data-types","framework","functional-programming","functions","operators","swift","swiftz"],"latest_commit_sha":null,"homepage":"http://47degrees.github.io/second-bridge/","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xebia-functional.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-03T12:38:22.000Z","updated_at":"2023-10-21T10:01:18.361Z","dependencies_parsed_at":"2022-09-02T18:23:05.523Z","dependency_job_id":null,"html_url":"https://github.com/xebia-functional/second-bridge","commit_stats":null,"previous_names":["47degrees/second-bridge"],"tags_count":3,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xebia-functional%2Fsecond-bridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xebia-functional%2Fsecond-bridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xebia-functional%2Fsecond-bridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xebia-functional%2Fsecond-bridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xebia-functional","download_url":"https://codeload.github.com/xebia-functional/second-bridge/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238722711,"owners_count":19519801,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cocoapods","data-types","framework","functional-programming","functions","operators","swift","swiftz"],"created_at":"2025-02-13T19:37:33.713Z","updated_at":"2025-10-28T21:30:42.991Z","avatar_url":"https://github.com/xebia-functional.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"Second Bridge\n=============\n\n**[Second Bridge](http://47deg.github.io/second-bridge)** is a Swift framework for functional programming. Our goal is to make Swift development on par with other functional languages like Scala by adding new data types, functions and operators.\n\nThis project depends on the awesome [Swiftz](https://github.com/typelift/Swiftz) framework, that defines functional data structures, functions, idioms, and extensions that augment the Swift standard library.\n\nInstallation\n==========\n\n**Second Bridge** supports the **CocoaPods** dependency manager. To install the framework in your project, place the following in your Podfile:\n\n```\nplatform :ios, '8.0'\nuse_frameworks!\n\n// (... other pods ...)\npod 'SecondBridge', :git =\u003e 'https://github.com/47deg/second-bridge.git'\n```\nBy running `pod install` or `pod update` you should have **Second Bridge** in your workspace ready to go!\n\nFeatures\n===========\n\n####  DATA-TYPES PROTOCOLS\n\n**Traversable**\n\nProtocols like **Traversable** and **Iterable** will make it easier for you to expand the current data-types available. If you need to create a new data-type, just by implementing the following three methods your type will have access to the 40-something functions available in **Second Bridge**:\n\n```C\n// Traverse all items of the instance, and call the provided function on each one.\nfunc foreach(f: (ItemType) -\u003e ())\n\n// Build a new instance of the same Traversable type with the elements contained\n// in the `elements` array (i.e.: returned from the **T functions).\nclass func build(elements: [ItemType]) -\u003e Self \n\n// Build a new instance of the same Traversable type with the elements contained in the provided\n// Traversable instance. Users calling this function are responsible of transforming the data of each\n// item to a valid ItemType suitable for the current Traversable class. \nclass func buildFromTraversable\u003cU where U : Traversable\u003e(traversable: U) -\u003e Self\n```\n\nThe following **global** functions are available for any **Traversable-conforming** type. Those are based on the main ones available in Scala for Traversable-derived types:\n\n* **collectT**: Returns an array containing the results of mapping a partial function `f` over a set of the elements of this Traversable that match the condition defined in `f`'s `isDefinedAt`.\n* **countT**: Returns the number of elements of this Traversable satisfy the given predicate.\n* **dropT**: Selects all elements except the first n ones.\n* **dropRightT**: Selects all elements except the last n ones.\n* **dropWhileT**: Drops the longest prefix of elements that satisfy a predicate.\n* **existsT**: Returns true if at least one of its elements of this Traversable satisfy the given predicate.\n* **findT**: Returns the first element of this Traversable that satisfy the given predicate `p`, if any.\n* **filterT**: Returns a Traversable containing all the values from the current traversable that satisfy the `includeElement` closure.\n* **filterNotT**: Returns an array containing all the values from the current traversable except those that satisfy the `excludeElement` closure.\n* **flatMapT**: Returns the result of applying `transform` on each element of the traversable, and then flattening the results into an array. You can create a new Traversable from the results of the flatMap application by calling function Traversable.build and passing its results to it.\n* **foldLeftT**: Returns the result of repeatedly calling combine with an accumulated value initialized to `initial` and each element of the current traversable from right to left. A reversal equivalent to `reduceT`/`foldLeftT`.\n* **foldRightT**: Returns the result of repeatedly calling combine with an accumulated value initialized to `initial` and each element of the current traversable from left to right. Equivalent to `reduceT`.\n* **forAllT**: Returns true if all the elements of this Traversable satisfy the given predicate.\n* **groupByT**: Partitions this Traversable into a map of Traversables according to some discriminator function defined by the function `f`.\n* **headT**: Returns the first element of the Traversable or a nil if it's empty. \n* **initT**: Returns all the elements of this Traversable except the last one.\n* **isEmptyT**: Returns true if this Traversable doesn't contain any elements.\n* **lastT**: Returns the last element of the Traversable or a nil if it's empty.\n* **mapT**: Returns an array containing the results of mapping `transform` over the elements of the provided Traversable.\n* **mapConserveT**: Returns a traversable containing the results of mapping `transform` over its elements. The resulting elements are guaranteed to be the same type as the items of the provided traversable.\n* **mkStringT**: Returns a string representation of all the elements within the Traversable, separated by the provided separator and enclosed by the `start` and `end` strings.\n* **nonEmptyT**: Returns true if this Traversable contains elements.\n* **partitionT**: Returns a tuple containing the results of splitting the Traversable according to a predicate. The first traversable in the tuple contains those elements which satisfy the predicate, while the second contains those which don't.\n* **reduceT**: Returns the result of repeatedly calling combine with an accumulated value initialized to `initial` and each element of the current traversable.\n* **reverseT**: Returns a traversable with elements in inverse order.\n* **sizeT**: Returns the number of elements contained in this Traversable.\n* **sliceT**: Returns a Traversable made of the elements from `source` which satisfy the invariant: `from \u003c= indexOf(x) \u003c until`.\n* **sortWithT**: Returns a new Traversable containing all the elements from the provided one, but sorted by a predicate `p`.\n* **spanT**: Returns a tuple containing the results of splitting the Traversable according to a predicate. The first traversable in the tuple contains the first elements that satisfy the predicate `p`, while the second contains all elements after those.\n* **splitAtT**: Returns a tuple containing the results of splitting the Traversable at the given position.\n* **tailT**: Returns a new Traversable containing all the elements of the provided one except for the first element.\n* **takeT**: Returns a new Traversable of the same type containing the first n elements.\n* **takeRightT**: Returns a new Traversable containing the last n elements.\n* **takeWhileT**: Takes the longest prefix of elements that satisfy a predicate.\n* **toArrayT**: Returns a standard array containing the elements of this Traversable.\n* **toListT**: Returns a singly-linked list containing the elements of this Traversable.\n* **unionT**: Returns a new Traversable containing all the elements from the two provided Traversables.\n\n**Iterable**\n\nAny Traversable-conforming data type that also implements the standard **SequenceType** protocol (defining an iterator to step one-by-one through the collection's elements) instantly becomes an **Iterable**. Iterables have instant access to the next functions, also based on their **Scala** counter-parts:\n\n* **grouped**: Returns an array of Iterables of size `n`, comprising all the elements of the provided Iterable.\n* **sameElements**: Returns true if the two Iterables contain the same elements in the same order.\n* **sliding**: Returns an array of Iterables, being the result of grouping chunks of size `n` while traversing through a sliding window of size `windowSize`.\n* **sliding**: Returns an array of Iterables, being the result of grouping chunks of size `n` while traversing through a sliding window of size 1.\n* **zip**: Returns an array of tuples, each containing the corresponding elements from the provided Iterables.\n* **zipAll**: Returns an array of tuples, each containing the corresponding elements from the provided Iterables. If the two sources aren't the same size, zipAll will fill the gaps by using the provided default items (if any).\n* **zipWithIndex**: Returns an array of tuples, each containing an element from the provided Iterable and its index.\n\n#### DATA TYPES\n\n**ArrayT**\n\nAn **immutable**, **traversable** and **typed** Array.\n\n```swift\nimport SecondBridge\n\nlet anArray : ArrayT\u003cInt\u003e = [1, 2, 3, 4, 5, 6] \nlet list = anArray.toList()\nanArray.isEmpty()  // False\nanArray.size()  // 6\nanArray.drop(4)  // [5,6]\nanArray.filterNot({ $0 == 1 })  // [2, 3, 4, 5, 6]\n```\n\n**BinarySearchTree**\n\nAn **immutable** binary search tree. \n\n```swift\nimport SecondBridge\n\nlet tree = BinarySearchTree.Node(2, left: BinarySearchTree.Empty, right: BinarySearchTree.Empty) // [. 2 .]\nlet tree2 = tree.add(4).add(8).add(5).add(1).add(3).add(7).add(10)  // [[. 1 .] 2 [[. 3 .] 4 [[. 5 [. 7 .]] 8 [. 10 .]]]]\nlet tree3 = tree.remove(5)  // [[. 1 .] 2 [[. 3 .] 4 [[. 7 .] 8 [. 10 .]]]]\ntree2.count() // 8\ntree2.search(1)  // true\ntree2.inOrderTraversal() // [1, 2, 3, 4, 5, 7, 8, 10]\n\n```\n\n**ListT**\n\nAn **immutable**, **traversable** and **typed** List.\n\n```swift\nimport SecondBridge\n\nlet a : ListT\u003cInt\u003e = [1,2,3,4]\na.head()  // 1\na.tail()  // [2,3,4]\na.length()  // 4\na.filter({$0 % 3 == 0})  //  [1,2,4]\n```\n\n[Interactive Playground about Lists](https://github.com/47deg/swift-poc/blob/master/Playgrounds/ExampleList.playground/Contents.swift)\n\n**Map**\n\nAn **immutable**, **unordered**, **traversable** and **iterable** collection containing pairs of keys and values. Values are typed, but **Second Bridge** supports several types of keys within one Map (i.e.: **Int**, **Float** and **String**) inside a container called `HashableAny`.\n\n```C\nimport SecondBridge\n\nlet map : Map\u003cInt\u003e = [\"a\" : 1, 2 : 2, 4.5 : 3]\nlet map2 = map + [\"c\" : 4]\t\t\t// map2 = [\"a\" : 1, 2 : 2, 4.5 : 3, \"c\" : 4]\nlet map3 = map2 + (\"d\", 5)\t\t\t// map3 = [\"a\" : 1, 2 : 2, 4.5 : 3, \"c\" : 4, \"d\" : 5]\nlet map4 = map3 + [(\"foo\", 7), (\"bar\", 8)]\t// map4 = [\"a\" : 1, 2 : 2, 4.5 : 3, \"c\" : 4, \"d\" : 5, \"foo\" : 7,  \"bar\" : 8]\n\nlet map5 = map4 - \"d\"\t\t\t\t\t\t// map5 = [\"a\" : 1, 2 : 2, 4.5 : 3, \"c\" : 4, \"foo\" : 7,  \"bar\" : 8]\nlet map 6 = map5 -- [\"foo\", \"bar\"]\t\t\t// map6 = [\"a\" : 1, 2 : 2, 4.5 : 3, \"c\" : 4]\n\nlet filteredMap = map6.filter({ (value) -\u003e Bool in (value as Int) \u003c 3})  // (\"a\" : 1, 2 : 2)\nlet reducedResult = map6.reduceByValue(0, combine: +)   \t\t\t\t\t// 10\nlet values = map6.values \t\t\t\t\t\t\t\t\t\t\t\t// [1, 2, 3, 4]\n\n```\n[Interactive Playground about Maps](https://github.com/47deg/swift-poc/blob/master/Playgrounds/ExampleMap.playground/Contents.swift)\n\n**Stack**\n\nAn **immutable**, **traversable**, **iterable** and **typed** LIFO stack.\n\n```swift\nimport SecondBridge\n\nlet stack = Stack\u003cInt\u003e()\nlet stack2 = stack.push(1).push(2).push(3)    // top -\u003e 3, 2, 1 \u003c- bottom\n\nlet topStack = stack2.top() // 3\nlet popStack = stack2.pop()\t// (3, Stack[2, 1])\n```\n\n* [Interactive Playground about Stacks](https://github.com/47deg/swift-poc/blob/master/Playgrounds/ExampleStack.playground/Contents.swift)\n* [Interactive Playground to showcase the use of Stacks and functional algorithms to solve the N-Queens problem](https://github.com/47deg/swift-poc/blob/master/Playgrounds/ExampleNQueens.playground/Contents.swift)\n\n**Vector**\n\nAn **immutable**, **traversable**, **iterable** and **typed** **Persistent Bit-partitioned Vector Trie**, based on Haskell and Scala's Vector implementations.\n\n```swift\nimport SecondBridge\n\nlet vector = Vector\u003cInt\u003e()\t\t// Empty vector\nvector = vector.append(1) \t\t// [1]\nvector = vector + 2\t\t\t\t// [1, 2]\nvector += 3\t\t\t\t\t\t// [1, 2, 3]\nlet value = vector[1]\t\t\t// 2\nvector = vector.pop()\t\t\t// [1, 2]\n```\n\n[Interactive Playground about Vectors](https://github.com/47deg/swift-poc/blob/master/Playgrounds/ExampleVector.playground/Contents.swift)\n\n####  FUNCTIONS\n\n**Partial Function**\n\nA partial function are those whose execution is restricted to a certain set of values, defined by the method `isDefinedAt`. This allows developers to set certain conditions to their functions. An easy to understand example is a divider function, whose execution is restricted to dividers equal to zero. As with **Scala**'s partial functions, you are allowed to execute them even by using their restricted set of parameters. But you have access to the `isDefinedAt` function that tells you if it's safe to call.\n\n**Second Bridge** defines several custom operators that makes creating partial functions really easy. Just by joining two closures with the `|-\u003e` operator, we create a partial function (the first closure must return a Bool, thus defining the conditions under which this function works).\n\nOne important aspect of partial functions is that by combining them you can create meaningful pieces of code that define algorithms. i.e.: you can create a combined function that performs an operation or another, depending on the received parameter. You have access to other custom operators like `|||\u003e` (*OR*), `\u003e\u003e\u003e` (*AND THEN*), and  `∫` (*function definition*). One quick example:\n\n```swift\nimport SecondBridge\n\nlet doubleEvens = { $0 % 2 == 0 } |-\u003e { $0 * 2 }\t\t// Multiply by 2 any even number\nlet tripleOdds = { $0 % 2 != 0 } |-\u003e { $0 * 3 }\t\t\t// Multiply by 3 any odd number\nlet addFive = ∫(+5)\t\t\t\t\t\t\t\t\t  // Regular function to add five to any number\n\nlet opOrElseOp = doubleEvens |||\u003e tripleOdds\t\t// If receiving an even, double it. If not, triple it.\nlet opOrElseAndThenOp = doubleEvens |||\u003e tripleOdds \u003e\u003e\u003e addFive\t// If receiving an even, double it. If not, triple it. Then, add five to the result.\n\nopOrElseOp.apply(3)\t\t\t// 9\nopOrElseOp.apply(4)\t\t\t// 8\nopOrElseAndThenOp.apply(3)\t// 14\nopOrElseAndThenOp.apply(4)\t// 13\n```\n\nPartial functions also gives us the ability to perform **complex pattern matching sets**, more powerful than Swift's standard **switch** block, by using our **match** function:\n\n```swift\nimport SecondBridge\nlet matchTest = match({(item: Int) -\u003e Bool in item == 0 } |-\u003e {(Int) -\u003e String in return \"Zero\"},\n                              {(item: Int) -\u003e Bool in item == 1 } |-\u003e {(Int) -\u003e String in return \"One\"},\n                              {(item: Int) -\u003e Bool in item == 2 } |-\u003e {(Int) -\u003e String in return \"Two\"},\n                              {(item: Int) -\u003e Bool in item \u003e 2 } |-\u003e {(Int) -\u003e String in return \"Moar!\"})\n                              \nmatchTest.apply(0)\t\t\t// \"Zero\"\nmatchTest.apply(1)\t\t\t// \"One\"\nmatchTest.apply(1000)\t\t// \"Moar!\"\n```\n\n####  UTILS\n\n**Try**\n\n`Try` is a monad that encapsulates an operation that can fail and throw an exception. As you may be aware, Swift now supports `do-try-catch` blocks to handle operations that can fail. `Try` can wrap throwable functions (those marked with the `throws` keyword) to handle these failures for you. The result of the wrapped operation is stored in a `TryMatcher.Success(x)` if it's a valid result `x`, or `TryMatcher.Failure(ex)` if the operation has thrown an `ex` exception.\n\n```swift\nimport SecondBridge\n\n// Throwable function\nfunc convertStringToInt(s: String) throws -\u003e Int {\n     if let parsedInt = Int(s) {\n         return parsedInt\n     } else {\n         throw ParseError.InvalidString\n     }\n}\n\nlet tryParseCorrectString = Try\u003cInt\u003e(try self.convertStringToInt(\"47\"))\ntryParseCorrectString.isFailure()\t\t\t\t\t// false\ntryParseCorrectString.isSuccess()\t\t\t\t\t// true\n\n// You can get the result of the operations through pattern matching...\nswitch tryParseCorrectString.matchResult {\n        case .Success(let value): print(\"Result is \\(value)\")\n        case .Failure(let ex): print(\"There has been an exception!\")\n}\n\n// ...or using convenience functions like getOrElse\nlet value = tryParseCorrectString.getOrElse(0)\t\t// 47\n\nlet tryParseIncorrectString = Try\u003cInt\u003e(try self.convertStringToInt(\"47 Degrees\"))\ntryParseCorrectString.isFailure()\t\t\t\t\t\t\t// true\ntryParseCorrectString.isSuccess()\t\t\t\t\t\t\t// false\nlet invalidValue = tryParseIncorrectString.getOrElse(666)   // 666\n\n// You can apply several Higher-Order Functions to Try instances\n// to apply functions to the encapsulated values:\nlet f = { (n: Int) -\u003e Int in n + 10 }\nlet mapCorrectResult = tryParseCorrectString.map(f).getOrElse(666)\t// 57\n\nlet filterCorrectResult = \n\ttryParseCorrectString.filter({ $0 != 47 })\t\t// .Failure(exception)\n\nfunc tryHalf(n: Int) -\u003e Try\u003cInt\u003e {\n\t// Returns a Try containing a function that divides any Int by two\n\t// ...\n}\nlet flatmapCorrectResultAgainstOKFunction = tryParseCorrectString.flatMap(tryHalf)\nflatmapCorrectResultAgainstOKFunction.isSuccess()\t// true\nflatmapCorrectResultAgainstOKFunction.getOrElse(1)\t// 23\n\n// You can also use `recover` and `recoverWith` to chain a set of\n// Partial Functions that can handle failures in your `Try`s:\nlet recoverResult = tryParseIncorrectString.recover({\n            (e: ErrorType) -\u003e Bool in\n                return true\n            } |-\u003e {(e: ErrorType) -\u003e (Int) in return 0})\n\nrecoverResult.isSuccess()\t\t\t\t\t\t\t\t// true\nlet recoverResultGet = recoverResult.getOrElse(1)\t\t// 0\n```\n\nSystem Requirements\n==================\n\nSecond Bridge supports iOS 8.0+ and Swift 2.0.\n\nContribute\n=========\n\nWe've tried to pack **Second Bridge** with many useful features from the **Scala** language. But considering all the work done there, we have a lot of ground to cover yet. That's why **47 Degrees wants YOU**! Second Bridge is **completely open-source**, and we're really looking forward to see what you can come up with! So if you're interested in Second Bridge and think that you've come up with a great feature to add... don't hesitate and send us a PR! We'll review and incorporate it to our code-base as soon as possible.\n\nLicense\n======\n**Copyright (C) 2015 47 Degrees, LLC** http://47deg.com hello@47deg.com\n\nLicensed under the **Apache License**, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxebia-functional%2Fsecond-bridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxebia-functional%2Fsecond-bridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxebia-functional%2Fsecond-bridge/lists"}