{"id":13396610,"url":"https://github.com/typelift/Basis","last_synced_at":"2025-03-13T23:31:37.501Z","repository":{"id":20498211,"uuid":"23776597","full_name":"typelift/Basis","owner":"typelift","description":"Pure Declarative Programming in Swift, Among Other Things","archived":false,"fork":false,"pushed_at":"2018-04-22T19:09:11.000Z","size":1291,"stargazers_count":316,"open_issues_count":0,"forks_count":13,"subscribers_count":18,"default_branch":"master","last_synced_at":"2024-07-31T18:17:44.536Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/typelift.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-09-08T02:10:00.000Z","updated_at":"2024-07-31T05:13:05.000Z","dependencies_parsed_at":"2022-09-09T11:41:30.063Z","dependency_job_id":null,"html_url":"https://github.com/typelift/Basis","commit_stats":null,"previous_names":["codafi/swift-extras"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelift%2FBasis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelift%2FBasis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelift%2FBasis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelift%2FBasis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/typelift","download_url":"https://codeload.github.com/typelift/Basis/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243500121,"owners_count":20300749,"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":[],"created_at":"2024-07-30T18:00:58.055Z","updated_at":"2025-03-13T23:31:37.135Z","avatar_url":"https://github.com/typelift.png","language":"Swift","funding_links":[],"categories":["Extensions","Libs","Utility [🔝](#readme)","Swift","Utilities and Extensions"],"sub_categories":["Utility"],"readme":"[![Build Status](https://travis-ci.org/typelift/Basis.svg?branch=master)](https://travis-ci.org/typelift/Basis)\n\nBasis\n=====\n\nThe Basis is an exploration of pure declarative programming and reasoning in \nSwift.  It by no means contains idiomatic code, but is instead intended to be a\nrepository for structures and ideas grounded in theory and mathematics.  Present\nin this repository are the necessary components to handle system interaction, \ncontrol, data flow, and a number of extensions and improvements to the Swift \nStandard Library and its structures.  Higher-level APIs and structures are \ngenerally excluded from the Basis to be implemented in other libraries.\n \n\nIt Gets Better!\n===============\n\nSwift provides an excellent opportunity to not just witness, but actually \nunderstand the formalization of many seemingly \"complex\" and abstract algebraic\nstructures without having to learn Haskell or ML or any of the other famous FP \nlanguages.  The documentation of types in this repository serves as a way to \ndeserialize a lot of the complex terms and jargon you may come across in these \nlanguages.  In this way, the Basis can be regarded as an encyclopedia of common\ntechniques and practices rather than a simple tutorial.  As such, if the \ndocumentation is too dense or unreadable, it means this library is failing one of \nits unit tests!  Clarification or rewrites of documentation to serve the broader \ncommunity are a priority and a promise.\n\nAny questions or comments should be made into issues, or pull requests if you \nfeel you can word it better.\n\nLet's make the world a bit less scary.\n\nGetting Started\n===============\n\nBasis comes wrapped up as a framework and iOS and OS X.  Simply add the project\nas a submodule, drag it to your project's file tree, and add it as a framework \ndependency for your build.  When all is said and done, just \n\n```\nimport Basis\n``` \n\nIntroduction\n============\n\nBecause The Basis places emphasis on functions over structures, the majority of\nthe functions in this repository are free and combinatorial.  Programming with\nthem then becomes a matter of selecting the proper combinators and compositional\noperators to achieve a desired type signature.\n\nTo take a famous example from Haskell:\n\n```Swift\n/// Sorts a list by recursively partitioning its elements into sublists around a\n/// pivot element.\nfunc quickSort\u003cT : Comparable\u003e(l : [T]) -\u003e [T] {\n    switch destruct(l) {\n        case .Empty:\n            return []\n        case let .Cons(x, xs):\n            let lesser  = xs.filter({ $0 \u003c x })\n            let greater = xs.filter({ $0 \u003e= x })\n            return quickSort(lesser) + [x] + quickSort(greater)\n    }\n}\n```\n\nOr perhaps a more convoluted example:\n\n```Swift\n/// Lift any 1-ary function to a function over Maybes.\nfunc liftA\u003cA, B\u003e(f : A -\u003e B) -\u003e Maybe\u003cA\u003e -\u003e Maybe\u003cB\u003e {\n    return { a in Maybe.pure(f) \u003c*\u003e a }\n}\n\n/// Lift any 2-ary function to a function over 2 Maybes.   \nfunc liftA2\u003cA, B, C\u003e(f : A -\u003e B -\u003e C) -\u003e Maybe\u003cA\u003e -\u003e Maybe\u003cB\u003e -\u003e Maybe\u003cC\u003e {\n    return { a in { b in Maybe.pure(f) \u003c*\u003e a \u003c*\u003e b } }\n}\n\n/// Lift any 3-ary function to a function over 3 Maybes.\nfunc liftA3\u003cA, B, C, D\u003e(f : A -\u003e B -\u003e C -\u003e D) -\u003e Maybe\u003cA\u003e -\u003e Maybe\u003cB\u003e -\u003e Maybe\u003cC\u003e -\u003e Maybe \u003cD\u003e {\n    return { a in { b in { c in Maybe.pure(f) \u003c*\u003e a \u003c*\u003e b \u003c*\u003e c } } }\n}\n```\n\nWith such an architecture in place, we can replace the classic `if-let` pattern\nfor optionals with calls to liftA2:\n\n```Swift\nlet a = Maybe.just(6)\nlet b = Maybe\u003cInt\u003e.nothing()\nlet c = Maybe.just(5)\n\n/// The result of adding 6 to Nothing is Nothing.\nlet nothing = liftA2(curry(+))(a)(b)\n\n/// The result of adding 5 and 6 is 11\nlet something = liftA2(curry(+))(a)(c)\n\n/// The result of packing 6, 5, and Nothing into a tuple is Nothing.\nlet noTupleHere = liftA3(pack3)(a)(b)(c)\n```\n\nWe can also exploit the tools Swift has given us for laziness and use them to\nbuild up infinite data structures despite having only a finite amount of memory.\n\n```Swift\n/// Returns a stream of every Natural Number.  Because Streams are built up \n/// iteratively only on demand, we needn't load every element at once, \n/// just one at a time as they are requested. \n///\n/// arr[0] == 0, arr[1] == 1, arr[2] == 2, ..., arr[n] == n\nlet naturalNumbers = iterate({ 1 + $0 })(0)\n\n/// Returns a stream consisting of only the items in a given list.\n///\n/// arr[0] == \"You\", arr[1] == \"Say\", arr[2] == \"Goodbye\", arr[4] == \"You\", ...\nlet butISayHello = cycle([\"You\", \"Say\", \"Goodbye\"])\n```\n\nOr even use laziness to help with control flow.\n\n```Swift\n/// A version of the factorial function that, while appearing recursive,\n/// actually evaluates in a constant amount of stack space.  As such it will\n/// never smash the stack no matter how large an input it is given. \nfunc noSmashFactorial(x : Double, _ acc : Double = 1.0) -\u003e Trampoline\u003cDouble\u003e {\n    if x \u003c= 1 {\n        return now(acc)\n    }\n    return later(noSmashFac(x - 1, acc * x))\n}\n\n/// The result of invoking this function is about 10^10^5.328.  Obviously, such\n/// a number is completely unrepresentable in any bitwidth Swift gives us.  The \n/// thing to notice is that we would have pushed 50,000 frames onto the stack.  \n/// Instead we push just 1. \nlet inf = noSmashFactorial(50000).run()\n```\n\nWe're no strangers to the Real World either.  Swift is a profoundly imperative\nlanguage at heart, but that doesn't mean we can't do something about it.  Enter\nthe IO Monad.  Our IO Monad is the incarnation of an effect that has yet to\nhappen.\n\n```Swift\n/// An effect that, when executed, will pause for input from the terminal, then\n/// shout it back at you.\nlet eff = interact(pack • map({ $0.toUpper() }) • unpack)\n/// ...\n/// Executes the effect with the current state of the world.\neff.unsafePerformIO()\n```\n\nSystem Requirements\n===================\n\nThe Basis supports OS X 10.9+ and iOS 7.0+\n\nLicense\n=======\n\nThe Basis is released under the MIT license.\n\nFurther Reading\n===============\n\n- [SML](http://en.wikipedia.org/wiki/Standard_ML)\n- [Haskell](http://haskell.org/)\n- [TTFP](https://www.cs.kent.ac.uk/people/staff/sjt/TTFP/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypelift%2FBasis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftypelift%2FBasis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypelift%2FBasis/lists"}