{"id":21710639,"url":"https://github.com/orakaro/swift-monad-maybe-reader-and-try","last_synced_at":"2025-04-12T17:30:47.630Z","repository":{"id":146360909,"uuid":"63381020","full_name":"orakaro/Swift-monad-Maybe-Reader-and-Try","owner":"orakaro","description":"Proof of concept: Maybe, Reader and Try monad","archived":false,"fork":false,"pushed_at":"2020-03-08T07:11:20.000Z","size":15,"stargazers_count":166,"open_issues_count":1,"forks_count":6,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-26T11:51:08.030Z","etag":null,"topics":["functor","monads","reader-monad","swift"],"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/orakaro.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,"governance":null}},"created_at":"2016-07-15T01:19:44.000Z","updated_at":"2025-03-10T10:15:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"ebce2df2-1613-46f8-ac06-02b049352f98","html_url":"https://github.com/orakaro/Swift-monad-Maybe-Reader-and-Try","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orakaro%2FSwift-monad-Maybe-Reader-and-Try","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orakaro%2FSwift-monad-Maybe-Reader-and-Try/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orakaro%2FSwift-monad-Maybe-Reader-and-Try/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orakaro%2FSwift-monad-Maybe-Reader-and-Try/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/orakaro","download_url":"https://codeload.github.com/orakaro/Swift-monad-Maybe-Reader-and-Try/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248604953,"owners_count":21132073,"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":["functor","monads","reader-monad","swift"],"created_at":"2024-11-25T23:16:39.348Z","updated_at":"2025-04-12T17:30:47.603Z","avatar_url":"https://github.com/orakaro.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Preface\r\n\r\nThis post has many awesome pictures which credits go to [Aditya Bhargava](https://twitter.com/_egonschiele). His original article\r\n[Functors, Applicatives, And Monads In Pictures](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html) is extremely well written, with sample code in Haskell though.\r\n\r\nIn this post I will try to provide proof of concept of Functor/Applicatives/Monad in pure Swift, plus example for using Reader Monad for Dependency Injection(DI), and the idea of Try monad concept from Scala.\r\n\r\n# Maybe is Functor\r\n\r\nWe all know the Optional Type (the ? mark) in Swift. We can define our option type named `Maybe` using enum.\r\n```swift\r\nenum Maybe\u003cT\u003e {\r\n\tcase Just(T)\r\n\tcase Nothing\r\n}\r\n```\r\nSimple enough! A `Maybe` type is a \"box\" which can contains the value or ... nothing\r\n\r\n![functor](http://adit.io/imgs/functors/context.png)\r\n\r\nThe interesting part come from here: we can define a `fmap` function which takes a normal function and a `Maybe` type, then return another `Maybe`\r\n\r\n![fmap](http://adit.io/imgs/functors/fmap_apply.png)\r\n\r\nHow does `fmap` look like? Well, its implement is not that hard\r\n```swift\r\nextension Maybe {\r\n\tfunc fmap\u003cU\u003e(f: T -\u003e U) -\u003e Maybe\u003cU\u003e {\r\n\t\tswitch self {\r\n\t\t\tcase .Just(let x): return .Just(f(x))\r\n\t\t\tcase .Nothing: return .Nothing\r\n\t\t}\r\n\t}\r\n}\r\n```\r\n\r\nAnd the \"magic\" above is actually not-so-magical. At this time, our `Maybe` type is already a **Functor**.\r\n![magic](http://adit.io/imgs/functors/fmap_just.png)\r\n\r\n# Maybe is Applicatives\r\nApplicatives is a type which can define the function `apply` that\r\n* Take a function wrapped in that type\r\n* Take also a value wrapped in that type\r\n* Then return a new value which is wrapped also\r\n\r\n![applicatives](http://adit.io/imgs/functors/applicative_just.png)\r\n\r\nI will define an `apply` function for `Maybe`\r\n```swift\r\nextension Maybe {\r\n\tfunc apply\u003cU\u003e(f: Maybe\u003cT -\u003e U\u003e) -\u003e Maybe\u003cU\u003e {\r\n\t\tswitch f {\r\n\t\t\tcase .Just(let JustF): return self.fmap(JustF)\r\n\t\t\tcase .Nothing: return .Nothing\r\n\t\t}\r\n\t}\r\n}\r\n```\r\nThat is it! Our `Maybe` now is both **Functor** and **Applicatives**.\r\n\r\n# Maybe is Monad\r\n\u003e How to learn about Monads:\r\n\u003e\r\n\u003e 1. Get a PhD in computer science.\r\n\u003e 2. Throw it away because you don’t need it for this section\r\n\r\n`Maybe` can be considered as a monad if it can define a function `flatmap` that\r\n* Take a function *which return type is* `Maybe`\r\n* Take also a value wrapped in `Maybe`\r\n* Return another `Maybe`\r\n\r\nLet's Swift! Here is our `flatMap` and bind operator `\u003e\u003e=`\r\n```swift\r\nextension Maybe {\r\n\tfunc flatMap\u003cU\u003e(f: T -\u003e Maybe\u003cU\u003e) -\u003e Maybe\u003cU\u003e {\r\n\t\tswitch self {\r\n\t\t\tcase .Just(let x): return (f(x))\r\n\t\t\tcase .Nothing: return .Nothing\r\n\t\t}\r\n\t}\r\n}\r\ninfix operator \u003e\u003e= { associativity left }\r\nfunc \u003e\u003e=\u003cT, U\u003e(a: Maybe\u003cT\u003e, f: T -\u003e Maybe\u003cU\u003e) -\u003e Maybe\u003cU\u003e {\r\n\treturn a.flatMap(f)\r\n}\r\n```\r\n\r\nSuppose that we already have a `half` function that return an `Maybe` type\r\n```swift\r\nfunc half(a: Int) -\u003e Maybe\u003cInt\u003e {\r\n\treturn a % 2 == 0 ? Maybe.Just(a / 2) : Maybe.Nothing\r\n}\r\n```\r\nThen with the `\u003e\u003e=` operator you can chain `Maybe` like:\r\n```swift\r\nMaybe.Just(20) \u003e\u003e= half \u003e\u003e= half \u003e\u003e= half\r\n```\r\n\r\nAnd this is how it is actually processed\r\n\r\n![half monad](http://adit.io/imgs/functors/monad_chain.png)\r\n\r\nNow our `Maybe` is **Functor**, **Applicatives** and also **Monad** as well.\r\n\r\n# A step further, the Reader monad\r\nIn this section I will introduce minimal version for one of three useful Monads: the Reader Monad\r\n```swift\r\nclass Reader\u003cE, A\u003e {\r\n\tlet g: E -\u003e A\r\n\tinit(g: E -\u003e A) {\r\n\t\tself.g = g\r\n\t}\r\n\tfunc apply(e: E) -\u003e A {\r\n\t\treturn g(e)\r\n\t}\r\n\tfunc map\u003cB\u003e(f: A -\u003e B) -\u003e Reader\u003cE, B\u003e {\r\n\t\treturn Reader\u003cE, B\u003e{ e in f(self.g(e)) }\r\n\t}\r\n\tfunc flatMap\u003cB\u003e(f: A -\u003e Reader\u003cE, B\u003e) -\u003e Reader\u003cE, B\u003e {\r\n\t\treturn Reader\u003cE, B\u003e{ e in f(self.g(e)).g(e) }\r\n\t}\r\n}\r\n```\r\n\r\n![flatMap](http://adit.io/imgs/functors/bind_def.png)\r\n\r\nAs you can see, we have `map`, and `flatMap` function here. This class type is both **Functor** and **Monad** at the same time. Very same with `Maybe` monad above, `Reader` can define infix operator and chain to whenever we want.\r\n```swift\r\ninfix operator \u003e\u003e= { associativity left }\r\nfunc \u003e\u003e=\u003cE, A, B\u003e(a: Reader\u003cE, A\u003e, f: A -\u003e Reader\u003cE, B\u003e) -\u003e Reader\u003cE, B\u003e {\r\n\treturn a.flatMap(f)\r\n}\r\n\r\nfunc half(i: Float ) -\u003e Reader\u003cFloat , Float\u003e {\r\n\treturn Reader{_ in i/2}\r\n}\r\nlet f = Reader{i in i} \u003e\u003e= half \u003e\u003e= half \u003e\u003e= half\r\nf.apply(20) // 2.5\r\n```\r\n\r\n\r\n## Why Reader monad matter\r\nReader monad take `g` function in `init` time. By switching (or *injecting*) this function, we can create our own Dependency Injection(DI) framework easily. Let's see an example:\r\n\r\nThis is our model:\r\n```swift\r\nstruct User {\r\n\tvar name: String\r\n\tvar age: Int\r\n}\r\nstruct DB {\r\n\tvar path: String\r\n\tfunc findUser(userName: String) -\u003e User {\r\n\t\t// DB Select operation\r\n\t\treturn User(name: userName, age: 29)\r\n\t}\r\n\tfunc updateUser(u: User) -\u003e Void {\r\n\t\t// DB Update operation\r\n\t\tprint(u.name + \" in: \" + path)\r\n\t}\r\n}\r\n```\r\nand usage:\r\n```swift\r\nlet dbPath = \"path_to_db\"\r\nfunc update(userName: String, newName: String) -\u003e Void {\r\n\tlet db = DB(path: dbPath)\r\n\tvar user = db.findUser(userName)\r\n\tuser.name = newName\r\n\tdb.updateUser(user)\r\n}\r\nupdate(\"dummy_id\", newName: \"Thor\")\r\n// Thor in: path_to_db\r\n```\r\nIn real life `DB` may be compicated and seperated as a whole infrastructure layer. Assume that `DB` can find an user by his name and update his information to the Database.\r\n\r\nThe problem is `update` function now holding a reference to `dbPath`, which I want to switch during test or runtime. I will rewrite the `update` function to return only a `Reader`\r\n```swift\r\nstruct Environment {\r\n\tvar path: String\r\n}\r\nfunc updateF(userName: String, newName: String) -\u003e Reader\u003cEnvironment, Void\u003e {\r\n\treturn Reader\u003cEnvironment, Void\u003e{ env in\r\n\t\tlet db = DB(path: env.path)\r\n\t\tvar user = db.findUser(userName)\r\n\t\tuser.name = newName\r\n\t\tdb.updateUser(user)\r\n\t}\r\n}\r\n```\r\nthen call `Reader.apply` later base on what passed through Environment variable.\r\n```swift\r\nlet test = Environment(path: \"path_to_sqlite\")\r\nlet production = Environment(path: \"path_to_realm\")\r\nupdateF(\"dummy_id\", newName: \"Thor\").apply(test)\r\n// Thor in: path_to_sqlite\r\nupdateF(\"dummy_id\", newName: \"Thor\").apply(production)\r\n// Thor in: path_to_realm\r\n```\r\n\r\n![whoa](http://adit.io/imgs/functors/whoa.png)\r\n\r\n# The Try Monad\r\nScala's `Try` type is a functional approach for error handling. Very likely to Optional (or `Maybe`), `Try` is a \"box\" that contains value or a *Throwable* if something has gone wrong. `Try` can be a Successful or a Failure.\r\n```swift\r\nenum Try\u003cT\u003e {\r\n\tcase Successful(T)\r\n\tcase Failure(ErrorType)\r\n\tinit(f: () throws -\u003e T) {\r\n\t\tdo {\r\n\t\t\tself = .Successful(try f())\r\n\t\t} catch {\r\n\t\t\tself = .Failure(error)\r\n\t\t}\r\n\t}\r\n}\r\n```\r\nTo make `Try` a functor/monad, I will add `map` and `flatMap` function\r\n```swift\r\nextension Try {\r\n\tfunc map\u003cU\u003e(f: T -\u003e U) -\u003e Try\u003cU\u003e {\r\n\t\tswitch self {\r\n\t\t\tcase .Successful(let value): return .Successful(f(value))\r\n\t\t\tcase .Failure(let error): return .Failure(error)\r\n\t\t}\r\n\t}\r\n\tfunc flatMap\u003cU\u003e(f: T -\u003e Try\u003cU\u003e) -\u003e Try\u003cU\u003e {\r\n\t\tswitch self {\r\n\t\t\tcase .Successful(let value): return f(value)\r\n\t\t\tcase .Failure(let error): return .Failure(error)\r\n\t\t}\r\n\t}\r\n}\r\n```\r\nWith an operation which can throws some ErrorType, just wrap them inside a Try and chain(with `map` and `flatMap`) to whenever you want. At every step the result will be a `Try` type. When you want the real value inside that box, just do a pattern matching.\r\n```swift\r\nenum DoomsdayComing: ErrorType {\r\n\tcase Boom\r\n\tcase Bang\r\n}\r\nlet endOfTheWorld = Try {\r\n\tthrow DoomsdayComing.Bang\r\n}\r\nlet result = Try {4/2}.flatMap { _ in endOfTheWorld}\r\nswitch result {\r\n\tcase .Successful(let value): print(value)\r\n\tcase .Failure(let error): print(error)\r\n}\r\n// Bang\r\n```\r\n\r\n# Conclusion\r\n1. A functor is a type that implements map.\r\n2. An applicative is a type that implements apply.\r\n3. A monad is a type that implements flatMap.\r\n\r\n![compare](http://adit.io/imgs/functors/recap.png)\r\n\r\n* `Maybe` have map, apply and flatMap, so it is a functor, an applicative, and a monad.\r\n* `Reader` is a monad which can be used for DI(Dependency Injection)\r\n* `Try` is a monad, and so as `Future`, `Signal` or `Observable` (see their `flatMap` implement!)\r\n\r\n![monad everywhere](http://sortega.github.io/assets/functional_patterns/monads.jpg)\r\n\r\nThanks for reading this article and feel free to give any feedback or suggestion. You can open a pull request or reach me out at [@dtvd88](https://twitter.com/dtvd88). If you want to play around with above class, clone this repo and open the Playground.\r\n\r\nMany thanks to [Aditya Bhargava](https://twitter.com/_egonschiele) for his awesome blog.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forakaro%2Fswift-monad-maybe-reader-and-try","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Forakaro%2Fswift-monad-maybe-reader-and-try","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forakaro%2Fswift-monad-maybe-reader-and-try/lists"}