{"id":13850723,"url":"https://github.com/rafbcampos/naive_functional_programming","last_synced_at":"2026-02-12T08:25:37.686Z","repository":{"id":40794123,"uuid":"241228803","full_name":"rafbcampos/naive_functional_programming","owner":"rafbcampos","description":"A naive approach to functional programming using TypeScript","archived":false,"fork":false,"pushed_at":"2023-01-05T16:24:59.000Z","size":383,"stargazers_count":139,"open_issues_count":12,"forks_count":2,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-08-05T20:33:10.115Z","etag":null,"topics":["category-theory","functional-programming","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","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/rafbcampos.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":"2020-02-17T23:22:43.000Z","updated_at":"2024-05-02T10:56:27.000Z","dependencies_parsed_at":"2023-02-04T07:31:14.319Z","dependency_job_id":null,"html_url":"https://github.com/rafbcampos/naive_functional_programming","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/rafbcampos%2Fnaive_functional_programming","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafbcampos%2Fnaive_functional_programming/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafbcampos%2Fnaive_functional_programming/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafbcampos%2Fnaive_functional_programming/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rafbcampos","download_url":"https://codeload.github.com/rafbcampos/naive_functional_programming/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225844875,"owners_count":17533160,"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":["category-theory","functional-programming","typescript"],"created_at":"2024-08-04T20:01:28.242Z","updated_at":"2026-02-12T08:25:37.639Z","avatar_url":"https://github.com/rafbcampos.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# A naive approach to functional programming\n\nI'm trying to learn functional programming, and that could be quite overwhelming.\n\nSearch for functional programming often results in a bunch of unreadable lingoes (for me at least), articles trying to wrap the F-word in new names like 'mappable', or people that do not understand it, but are writing tutorials either way.\n\n**That isn't what I'm trying to do here. What I'm doing is learn in public.**\n\n## Some real functional programming content\n\nFirst, and that is worth even if you do not keep reading to the end, check this out:\n\n- [Professor Frisby Introduces Composable Functional JavaScript by Brian Lonsdorf](https://egghead.io/courses/professor-frisby-introduces-composable-functional-javascript) - This is an incredible free course, and is the source of most of the stuff you are going to see here, so do a favor to yourself and watch it.\n\n- [Category Theory by Bartosz Milewski](https://www.youtube.com/watch?v=I8LbkfSSR58\u0026list=PLbgaMIhjbmEnaH_LTkxLI7FMa2HsnawM_) - If you're feeling adventurous and want to discover the crazy world of the Category Theory, watch this series of videos (I'm watching for the second time, and probably I'll need at least one more, but worth it).\n\nNow that I pointed you to people who know what they're talking about, I'm free to throw here that stuff that is in my head while I'm trying to figure that out.\n\n**Table of content**\n\n- [A naive approach to functional programming](#a-naive-approach-to-functional-programming)\n  - [Some real functional programming content](#some-real-functional-programming-content)\n  - [What?! Why?!](#what-why)\n  - [Composition](#composition)\n    - [Associativity](#associativity)\n    - [Identity](#identity)\n  - [Tools](#tools)\n  - [Identity Functor](#identity-functor)\n  - [Either](#either)\n  - [Applicative](#applicative)\n  - [Natural Transformation](#natural-transformation)\n  - [Isomorphism](#isomorphism)\n  - [Higher Kinded Types](#higher-kinded-types)\n  - [I/O](#io)\n  - [Algebraic Data Types](#algebraic-data-types)\n    - [Products/Conjunctions - pairs, tuples, records](#products-conjunctions---pairs--tuples--records)\n    - [Sums/Alternatives - Either](#sums-alternatives---either)\n    - [Exponentials/Implication - Function types](#exponentials-implication---function-types)\n    - [Unit/Truth - Void](#unit-truth---void)\n  - [State Monad](#state-monad)\n  - [Reader Monad](#reader-monad)\n  - [Pattern Matching](#pattern-matching)\n  - [Contributing](#contributing)\n  - [License](#license)\n\n## What?! Why?!\n\nAs far as I understand, Category Theory is a way to try to structure things through abstraction.\n\nInstead of walking in the streets trying to draw a map, we use a satellite picture for that.\n\nWe have these **objects** and the **relations** between them, and we're forbidden to look into the objects (not because we want to punish ourselves, but to create structures that serve to more than one type of category), so **all our assertions need to be inferred from those relations, called morphisms**.\n\n\u003e Let's stop right there. Why on earth I need to engage in this math theory?! I'm not trying to understand the entire world through math. I want to become a better programmer.\n\nOk, I'm with you on that. But do you remember that those math guys have this constraint of only seeing things through their relations? If you take **types as a Category and function as morphisms**, you end up with a bunch of knowledge on how to deal with functions and can apply that to make your code better. I'm talking about **composition and predictability**.\n\nSo the main goal is to write **code that is predictable and easy to reason about**, and we can get that if we fit our functions and data structures into the Category Theory laws.\n\n## Composition\n\nCategory Theory is all about composition. We only have the morphism/arrows/functions to look at, since we're not allowed to check out the object's properties. So all the theory is based on these arrows and how to compose them.\n\nThe most common graphic representation we get when we start to search for Category Theory is:\n\n![Composition](https://res.cloudinary.com/alohawav/image/upload/v1582603319/Screen_Shot_2020-02-24_at_10.00.52_PM_ydxc0b.png)\n\nIf we have a function from A to B and another one from B to C, we must have a function A to C:\n\n```typescript\nconst f = (x: string) =\u003e x.length \u003e 0;\nconst g = (x: boolean) =\u003e (x ? 1 : 0);\n// Composing g after f:\nconst h = (x: string) =\u003e g(f(x));\n```\n\nAnd there is some laws:\n\n### Associativity\n\nTaking:\n\n```typescript\ntype f = \u003cA, B\u003e(x: A) =\u003e B;\ntype g = \u003cB, C\u003e(x: B) =\u003e C;\ntype h = \u003cC, D\u003e(x: C) =\u003e D;\n```\n\nWe have: `h . (g . f) == (h . g) . f == h . g . f`\n\nAfter all it all translates to `x =\u003e h(g(f(x)))`\n\n### Identity\n\nFor every object, there is always a function that returns itself (identity): `id = x =\u003e x`\n\n## Tools\n\nFirst, we need to use **pure functions**.\n\nThere is a bunch of rules to check a function as pure, but I'll stick with: **referential transparency**, that translates to I can swap my function invocation for the value it returns, like a lookup table. So, for that, no global variables, no side effects.\n\n\u003e I knew it! I work with Web Apps, my life is side effects: DOM manipulation, users inputs, Ajax calls, are you crazy?!\n\nRelax, take a deep breath 🧘‍♂️. We'll continue to do all that, believe me.\n\nAlso, we need **currying** that's a **partial application** where the end function always expect one argument (function arity 1). Languages like Haskel have that into it, but with JS we need to create or use a lib for that.\n\nOk, but there are more than pure functions. I'll throw a bunch of **loose definitions** here, so we can feel more comfortable when I talk Category Theory terms (and of course, it's valid to remember that's what I got about them):\n\n- Functors = A type that implements a `map` (not related to iteration, but applying a function on its value) **preserving composition** (`F(x).map(f).map(g) === F(x).map(g(f(x)))`) and **identity** (`F(x).map(x =\u003e x) = F(x)`).\n\n- Pointed Functors = Functor that implements an `of` method (that is a way to throw a value inside our container).\n\n- Applicative Functors = Functor that implements the method `ap` (apply the value of one container on the value of another container, remember, the value can be a function).\n\n- Semigroups = A type that implements a `concat` method that is **associativity**, that means `'Hello' + ('World' + '!') = ('Hello' + 'World') + '!'`\n\n- Monoids = It's a semigroup that has an `empty` method. In other words, it's safe to work no matter the number of elements: `empty string + 'all fine' = 'all fine'` no errors in our dear console.\n\n- Monads = Is a pointed functor that implements a `flatMap` or `chain` method (instead of nested Monads, it'll return a unidimensional Monad);\n\n- Natural transformation = FunctorA(value) =\u003e FunctorB(value)\n\n- Isomorphism = You can change from a type to another and vice-versa without losing information.\n\nI already can see people coming with torches and forks, to punish me for all the nonsense that I put here. But hold your horses. **That's a living document from my learning process, and that's what I get so far**.\n\n\u003e Ok, ok. But I'm starting to lose my interest. Can we see some code? I want to check how to implement all of that!\n\nFair enough. Let's move on.\n\n## Identity Functor\n\nHave you ever saw those Category Theory diagrams, where there is a dot, and an arrow that goes from that dot to itself?\n\nThose are identity functors. In our case, where our category is a set of types, they're endofunctors (because they map to the same set).\n\n\u003e Ok, but why would I be interested in such a thing, a functor that maps to itself?\n\nBecause that's our **ticket for the marvelous world of composition**.\n\nWe're going to put our value inside this container (functor) and use its `map` method to apply a function on its value and then return another functor to keep that going, till we finish with our operations and redeem our result using `fold`.\n\nFirst, let's define our Identity Functor:\n\n```typescript\ninterface Identity\u003cA\u003e {\n  map: \u003cB\u003e(f: (x: A) =\u003e B) =\u003e Identity\u003cB\u003e;\n  chain: \u003cB\u003e(f: (x: A) =\u003e Identity\u003cB\u003e) =\u003e Identity\u003cB\u003e;\n  fold: \u003cB\u003e(f: (x: A) =\u003e B) =\u003e B;\n  inspect: () =\u003e string;\n}\n\nconst identity = \u003cA\u003e(value: A): Identity\u003cA\u003e =\u003e ({\n  map: \u003cB\u003e(f: (x: A) =\u003e B) =\u003e identity\u003cB\u003e(f(value)),\n  chain: \u003cB\u003e(f: (x: A) =\u003e Identity\u003cB\u003e) =\u003e f(value),\n  fold: \u003cB\u003e(f: (x: A) =\u003e B) =\u003e f(value),\n  inspect: () =\u003e `Identity(${value})`\n});\n```\n\nThere are five methods here:\n\n- **map**: We apply a function to our value and put the result back in a functor to keep composing.\n- **chain**: Imagine that the function that you want to `map` returns another `Identity`. In that case, we'll end up with `Identity(Identity(value))`. Chain flat that, resulting in a single `Identity(value)`.\n- **fold**: It's tough, but sooner or later, our value needs to leave the cozy and secure functor.\n- **inspect**: Friendly console.\n\n\u003e Wait a minute. You said five methods, but there are only four here!\n\nYeap, the `identity` call has the same effect of the `of` method, that is the way to insert the value inside our functor.\n\n## Either\n\nAnd how about conditional constructs and error handler? Can functional programming improve that aspect of coding?\n\nYes, it can!\n\nIn this [talk](https://www.youtube.com/watch?v=E8I19uA-wGY) Scott Wlaschin uses this Railway Track model:\n\n![Railway Track Model](https://res.cloudinary.com/alohawav/image/upload/v1581997913/railwayTrackModel_jfnynj.png)\n\nHere we have functions that can return two different things, and we have a functor that can help us with that called Either:\n\n```typescript\ninterface Either\u003cL, R\u003e {\n  map: \u003cB\u003e(f: (x: R) =\u003e B) =\u003e Either\u003cL, B\u003e;\n  chain: \u003cB, C\u003e(f: (x: R) =\u003e Either\u003cB, C\u003e) =\u003e Either\u003cL, R\u003e | Either\u003cB, C\u003e;\n  fold: \u003cB, C\u003e(onLeft: (x: L) =\u003e B, onRight: (x: R) =\u003e C) =\u003e B | C;\n  inspect: () =\u003e string;\n}\n\nconst either = \u003cL, R\u003e(left?: L, right?: R): Either\u003cL, R\u003e =\u003e ({\n  map: \u003cB\u003e(f: (x: R) =\u003e B) =\u003e\n    exist(right) ? either\u003cL, B\u003e(undefined, f(right as R)) : either\u003cL, B\u003e(left),\n  chain: \u003cB, C\u003e(f: (x: R) =\u003e Either\u003cB, C\u003e) =\u003e\n    exist(right) ? f(right as R) : either\u003cL, R\u003e(left),\n  fold: \u003cB, C\u003e(onLeft: (x: L) =\u003e B, onRight: (x: R) =\u003e C) =\u003e\n    exist(right) ? onRight(right as R) : onLeft(left as L),\n  inspect: () =\u003e (exist(right) ? `Right(${right})` : `Left(${left})`)\n});\n```\n\nThat serves to handle errors, if some pops up, we skip the other steps in our chain. But also for skipping unnecessary computation, imagine that we have three predicates, but we only need one to be true to pass to the next step. If the first one returns true, we don't need to compute the next two, we skip them and move on in our pipe.\n\n## Applicative\n\nI want to go rad and put our curried functions in our pipeline. However, I don't want to `fold` just for that.\n\nTo do so, I need to apply functors to functors:\n`F(x =\u003e x + 10) -\u003e F(10) = F(20)`.\n\nIn the end, we need a method `ap` in a Functor containing a function as value and call that passing another Functor with our expect argument into it:\n`ap: (functor) =\u003e functor.map(value)`\n\nA pointed functor with an `ap` method is called **applicative functor**.\n\nTyping that with TypeScript end up being impossible for me (TypeScript does not have higher-kinded types like Haskel, and I got lost within so many letters using HKT like in [fp-ts](https://github.com/gcanti/fp-ts)), so I cheated a little bit:\n\n```typescript\ninterface Applicative\u003cA, B\u003e {\n  ap: (i: Identity\u003cA\u003e) =\u003e Identity\u003cB\u003e;\n}\n\ninterface Applicative2\u003cA, B, C\u003e {\n  ap: (i: Identity\u003cA\u003e) =\u003e Applicative\u003cB, C\u003e;\n}\n\ninterface Applicative3\u003cA, B, C, D\u003e {\n  ap: (i: Identity\u003cA\u003e) =\u003e Applicative2\u003cB, C, D\u003e;\n}\n\nconst applicative = \u003cA, B\u003e(value: (x: A) =\u003e B): Applicative\u003cA, B\u003e =\u003e ({\n  ap: (i: Identity\u003cA\u003e) =\u003e i.map(value)\n});\n\nconst applicative2 = \u003cA, B, C\u003e(\n  value: (x: A) =\u003e (y: B) =\u003e C\n): Applicative2\u003cA, B, C\u003e =\u003e ({\n  ap: (i: Identity\u003cA\u003e) =\u003e applicative\u003cB, C\u003e(i.fold(value))\n});\n\nconst applicative3 = \u003cA, B, C, D\u003e(\n  value: (x: A) =\u003e (y: B) =\u003e (z: C) =\u003e D\n): Applicative3\u003cA, B, C, D\u003e =\u003e ({\n  ap: (i: Identity\u003cA\u003e) =\u003e applicative2\u003cB, C, D\u003e(i.fold(value))\n});\n```\n\nApplicative Functors are not only about currying but also they help us parallelism. In a case where we have a couple of fetch calls, and we wrap them in a functor:\n\n```typescript\nconst synchronousLongTask = () =\u003e {\n  // ...\n  return identity(\"txt\");\n};\n\n// sequential:\nsynchronousLongTask().chain(t1 =\u003e\n  synchronousLongTask().map(t2 =\u003e synchronousLongTask().map(t3 =\u003e t1 + t2 + t3))\n);\n\n// We have this waterfall effect, where we need to wait for the first `synchronousLongTask`\n// return to call the next one and so on.\n// But in our example, the calls do not depend on the predecessor.\n\n// They can be called in parallel:\n\nconst composeTxt = (txt1: string) =\u003e (txt2: string) =\u003e (txt3: string) =\u003e\n  txt1 + txt2 + txt3;\n\napplicative3(composeTxt)\n  .ap(synchronousLongTask())\n  .ap(synchronousLongTask())\n  .ap(synchronousLongTask());\n```\n\n## Natural Transformation\n\nWe saw that we could pass a function to a map method, let's say `a =\u003e b`, and get `F(a) =\u003e F(b)`. But how about on the Functor itself (`F(a) =\u003e G(a)`)?\n\nLet's use our Identity and Either:\n\n```typescript\nconst identityToEither = \u003cA\u003e(i: Identity\u003cA\u003e) =\u003e\n  i.fold(x =\u003e either\u003cundefined, A\u003e(undefined, x));\n```\n\nIn this point we already know that we need to respect some law to fit in the predictable Category world:\n\n`nt(x).map(f) === nt(x.map(f))`\n\nSo, we need to put our function to the test:\n\n```typescript\nidentityToEither(identity(10))\n  .map(x =\u003e x * x)\n  .inspect() === identityToEither(identity(10).map(x =\u003e x * x)).inspect();\n\n// true (fireworks)\n```\n\nFinally, now I can understand this:\n\n![Natural Transformation](https://res.cloudinary.com/alohawav/image/upload/v1582081476/nt_nxaoek.png)\n\nFollow the path ➡️ ⬇️ (red) is equal to go ⬇️ ➡️ (blue):\n\n`nt(F(a).map(f)) === nt(F(a)).map(f) === G`\n\nAnd of course, there is some more pro stuff like:\n\n⬇️ ↘️ ➡️ + P\n\n⬆️ ⬆️ ⬇️ ⬇️ ⬅️ ➡️ ⬅️ ➡️ + B + A + Start\n\n\u003e Haha! Pretty funny, it's a Konami Code, haha... But wait, I'm losing focus here. Why do I want to transform a functor in another?\n\nYou don't want to hammer a nail with a saw or cut a log with a hammer. In the same way, you use different functors for each type of task.\n\nHowever, the functions of your pipeline can return different functors, and we have Natural Transformations at our disposal to fit them in a new functor when we need the methods that it has to offer. Like we took a battery from a drilling machine into a circular saw (Okay, enough of analogies).\n\n## Isomorphism\n\nOk by now, we're starting to get the gist of morphisms (arrows), so let's put some spicy on it.\n\nWe saw a bunch of arrows from `a` to `b`. But what if we also have a morphism from `b` to `a`?\n\nIn this case, **they are no equal, but isomorphic**. We can map `a -\u003e b` and `b -\u003e a` **without losing information**.\n\n\u003e What?!\n\nI guess an example it's better than all my gibresh:\n\n```typescript\nconst insert = x =\u003e [x];\nconst extract = a =\u003e a[0];\n\nconst start = 10;\nconst advanceOneSpace = insert(start);\nconst goBackOneSpace = extract(advanceOneSpace);\n\nstart === goBackOneSpace; // True - I guess we're a stuck in this Monopoly game.\n```\n\nThat gives us the ability to use a natural transformation to temporarily put our value in another Functor, solve a task that suits its peculiarities, and then put it back into the original Functor.\n\n## Higher Kinded Types\n\nTill now, I'm dodging the TS inability to deal with generics of generics (F\u003c A \u003c B \u003e\u003e).\n\nHere an explanation of what is HKT and how we can simulate its behavior in TS: [Higher kinded types in TypeScript, static and fantasy land by gcanti](https://medium.com/@gcanti/higher-kinded-types-in-typescript-static-and-fantasy-land-d41c361d0dbe).\n\nIt seems it's time to try that out:\n\nSo now we have a Record of types. We can define them using HKT\u003c[Identifier], [Type]\u003e for functors holding values from a single type. Or HKT\u003c[Identifier], [TypeA], [TypeB]\u003e for functors that can hold A|B.\n\n```typescript\n// Higher Kinded Types\n\n// Unique type:\nexport interface URI2HKT\u003cA\u003e {}\nexport type URIS = keyof URI2HKT\u003cany\u003e;\nexport type HKT\u003cURI extends URIS, A\u003e = URI2HKT\u003cA\u003e[URI];\n\n// A | B:\nexport interface URI2HKT2\u003cA, B\u003e {}\nexport type URIS2 = keyof URI2HKT2\u003cany, any\u003e;\nexport type HKT2\u003cURI extends URIS2, A, B\u003e = URI2HKT2\u003cA, B\u003e[URI];\n```\n\nLike gcanti show in his Medium, I'm using [Module Augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation) to add each one of my functors:\n\n```typescript\n// src/Identity.ts:\ndeclare module \"./HKT\" {\n  interface URI2HKT\u003cA\u003e {\n    Identity: Identity\u003cA\u003e;\n  }\n}\n\n// src/Either.ts:\ndeclare module \"./HKT\" {\n  interface URI2HKT2\u003cA, B\u003e {\n    Either: Either\u003cA, B\u003e;\n  }\n}\n```\n\nWith that, I changed my first version of Applicative, that only can handle Identity Functors, for any Functor A, and create a new Applicative2 to deal with Functor A|B:\n\n```typescript\n// src/Applicative.ts:\nexport interface Applicative\u003cA, B\u003e {\n  ap: \u003cF extends URIS\u003e(fa: HKT\u003cF, A\u003e) =\u003e HKT\u003cF, B\u003e;\n}\n\nexport const applicative = \u003cA, B\u003e(value: (x: A) =\u003e B): Applicative\u003cA, B\u003e =\u003e ({\n  ap: \u003cF extends URIS\u003e(fa: HKT\u003cF, A\u003e) =\u003e fa.map(value)\n});\n\n// src/Applicative2.ts:\nexport interface Applicative2\u003cA, B\u003e {\n  ap: \u003cF extends URIS2, L\u003e(fea: HKT2\u003cF, L, A\u003e) =\u003e HKT2\u003cF, L, B\u003e;\n}\n\nexport const applicative2 = \u003cA, B\u003e(value: (x: A) =\u003e B): Applicative2\u003cA, B\u003e =\u003e ({\n  ap: \u003cF extends URIS2, L\u003e(fea: HKT2\u003cF, L, A\u003e) =\u003e fea.map(value)\n});\n```\n\n## I/O\n\nBear with me. That will be a crazy trip.\n\nI was researching about I/O. Especially how to fit user inputs (that can be everything) and system outputs (functions that return void) in our functional world.\n\nFirst, I find articles assuming that's a side effect, and I/O returns a thunk (delayed calculation). So that serves as a flag (**I'll leave the predictable world and go rad, so only call me in a safe place**).\n\nHowever, I find a different approach to this problem:\n\nIn this [video](https://www.youtube.com/watch?v=fCoQb-zqYDI), Tsoding reimplements the I/O monad, trying to answer that same question.\n\nMaybe we should change or perspective over the problem. Would a function that receives the state of the World and returns the state of the World be pure?\n\n```typescript\ntype IO = \u003cWorld\u003e(w: World) =\u003e World;\n```\n\n![math](https://media.giphy.com/media/26xBI73gWquCBBCDe/giphy.gif)\n\nIt's like instead of `any` we had a type `everything` and from it we can extract the user input, or insert a `console.log`.\n\n\u003e I'm not even bothering to discuss the `state of World` part, but when I use I/O in Haskell, I'm not passing anything to I/O.\n\nWell, what if you are doing it, but Haskell hides that from you?\n\n\u003e Why?\n\nUnless we're dealing with the multi-dimension scenario, you have a single World that is being modified and passed to another function.\n\nWorld1 -\u003e (someOperation) -\u003e World2 -\u003e (someOperation) -\u003e World3\n\nSo we're not allowed to reuse World1. To prevent the user from doing that, Haskell makes the World inaccessible for the user.\n\nEither way, going into the crazy World thing, or only deferring the evaluation of a side effect, we can have segments in our code, where we only deal with pure functions and points where the I/O (synchronous) or Task (asynchronous) side effect happens.\n\nAt the end (at least till the point I understand it), I/O is the same as creating a function to receive user input or read a file that returns Identity or Either:\n\n```typescript\nconst unsafe = (): Either\u003cstring, number\u003e =\u003e {\n  // ex.: get user input, parse to an Int or return 'error'\n};\n\nconst safe = (input: Either\u003cstring, number\u003e) =\u003e {\n  input\n    .map(x =\u003e x + 10)\n    .map(x =\u003e x * x)\n    .fold(\n      x =\u003e x,\n      x =\u003e x\n    );\n};\n\nsafe(unsafe());\n```\n\n## Algebraic Data Types\n\nFollowing [this Bartosz's talk](https://www.youtube.com/watch?v=LkqTLJK2API\u0026list=WL), we have four algebraic data types:\n\n- Unit\n- Products\n- Sums\n- Exponentials\n\nTheir names correspond to the number of possible values:\n\nTaking const setA = [true, false], const setB = [r,g, b]:\n\n- Unit: single value = `void`;\n- products: 6 possible results (2 \\* 3) in `pair\u003cA, B\u003e` = `[[true,r],[true,g],[true,b], [false,r],[false,g],[false,b]]`\n- sums: 5 possible results (2 + 3) in `A|B` = `[true, false, r, g, b]`\n- exponentials: 8 possible results (2^3), if we take the function type `B -\u003e A` = `[r =\u003e true, r =\u003e false, g =\u003e true, g =\u003e false, b =\u003e true, b =\u003e false, _ =\u003e false, _ =\u003e true]`\n\nIn type theory, whenever we define a type, we need to say how it's created (introduction) and how to use it (elimination), so let's try that out:\n\n### Products/Conjunctions - pairs, tuples, records\n\nTaking a Pair, as an example, we need two values to create it (intoduction), and `first` and `second` methods give us access to each one of them (elimination):\n\n```typescript\nconst pair = \u003cA, B\u003e(a: A) =\u003e (b: B) =\u003e ({\n  first: a,\n  second: b\n});\n```\n\n### Sums/Alternatives - Either\n\nHere we have a union type: `A|B`. We can introduce using our naive `either` implementation:\n\n```typescript\nconst x = either\u003cstring, number\u003e(undefined, 10);\nconst y = either\u003cstring, number\u003e(\"error\");\n```\n\nAnd to eliminate/use it we have the `fold` method:\n\n```typescript\nx.fold(console.error, console.log);\n```\n\n### Exponentials/Implication - Function types\n\nWe implement them using lambdas `(a: A) =\u003e B` and eliminate them calling the function.\n\n### Unit/Truth - Void\n\nIt's always available so that you can use it everywhere. And there is no elimination since there is no value in it.\n\n\u003e But how that relates to better programming?\n\nIt's all about composing. We compose small functions to perform a complex operation, and we can compose types, to hold complex data.\n\nScalar types (string, number, boolean) compose in more complex data types, like arrays, or objects. Types that, besides containing a value, bring with them a series of methods.\n\nAlgebraic data types are ways to compose types, embeded with algebra laws, that can help us solve complex cases like define List recursively as:\n\n```typescript\ntype List\u003cT\u003e = void | { head: T; tail: List\u003cT\u003e };\n```\n\nWhich makes sense for a lazily evaluated language as Haskell.\n\nSpeaking of that, check out the gvergnaud's implementation using generators: [lazy-list.js](https://gist.github.com/gvergnaud/6e9de8e06ef65e65f18dbd05523c7ca9).\n\n## State Monad\n\nFinally, let's talk about the state.\n\nWe saw that composition creates those pipes through which we pass our values and receive the results after they are processed.\n\nBut what if they need a state besides their inputs to run?\n\nOf course, we'll not rely on a global variable. We're functional programmers (or at least we wish). Give us some credit.\n\nThere is a way to keep all pure. We need to pass the state as input.\n\nThe state will go through the pipes with our values. So given the same state and value, we'll get the same result.\nHere, as usual, my naive implementation of a State Monad:\n\n```typescript\nexport interface State\u003cS, A\u003e {\n  runWith: (s: S) =\u003e [S, A];\n  chain: \u003cB\u003e(st: (a: A) =\u003e State\u003cS, B\u003e) =\u003e State\u003cS, B\u003e;\n  map: \u003cB\u003e(f: (a: A) =\u003e B) =\u003e State\u003cS, B\u003e;\n}\n\nexport const state = \u003cS, A\u003e(f: (s: S) =\u003e [S, A]): State\u003cS, A\u003e =\u003e ({\n  runWith: (s: S) =\u003e f(s),\n  chain\u003cB\u003e(st: (a: A) =\u003e State\u003cS, B\u003e) {\n    return state\u003cS, B\u003e(s1 =\u003e {\n      const [s2, a] = this.runWith(s1);\n      return st(a).runWith(s2);\n    });\n  },\n  map\u003cB\u003e(f: (a: A) =\u003e B) {\n    return state\u003cS, B\u003e(s1 =\u003e {\n      const [s2, a] = this.runWith(s1);\n      return [s2, f(a)];\n    });\n  }\n});\n```\n\nWe have almost an Applicative since we hold a function. But this function has this particular signature: `state =\u003e [state, A]`. Now, we return a pair of our state and value.\n\nYou pile up functions and then, in the end, call `runWith` and pass the initial value.\n\n```typescript\nconst initialState = true;\n\nconst state = state\u003cboolean, number\u003e(st =\u003e [st, 50]);\nconst process1 = (x: number) =\u003e x * 10;\nconst process2 = (x: number) =\u003e\n  state\u003cboolean, Either\u003cstring, number\u003e\u003e(st =\u003e\n    st\n      ? [st, either\u003cstring, number\u003e(undefined, x + 50)]\n      : [st, either\u003cstring, number\u003e(\"error\")]\n  );\nconst process3 = (x: number) =\u003e x + 10;\n\nconst x = state\n  .map(process1)\n  .chain(process2)\n  .map(e =\u003e e.map(process3))\n  .runWith(initialState)[1]\n  .fold(\n    x =\u003e x,\n    x =\u003e x\n  );\n\n// x = 560 (50 -\u003e 500 -\u003e 550 -\u003e 560)\n```\n\nIn this case, we composed some functions, including a function that returns `Either\u003cstring, number\u003e`.\n\nIt's quite elegant solution. In our example, we did not change the state, but it's possible with the `chain` method.\n\n## Reader Monad\n\nIn addition to states, our functions may need configuration. For these cases, we use the Reader Monad.\n\nThe good news is that since we already created the State Monad, we almost have the Reader Monad, with a little gotcha, we need to prevent the config change.\n\nSo our naive implementation would be:\n\n```typescript\nexport interface Reader\u003cC, A\u003e {\n  addConfig: (c: C) =\u003e [C, A];\n  chain: \u003cB\u003e(st: (a: A) =\u003e Reader\u003cC, B\u003e) =\u003e Reader\u003cC, B\u003e;\n  map: \u003cB\u003e(f: (a: A) =\u003e B) =\u003e Reader\u003cC, B\u003e;\n}\n\nexport const reader = \u003cC, A\u003e(f: (c: C) =\u003e [C, A]): Reader\u003cC, A\u003e =\u003e ({\n  addConfig: (c: C) =\u003e f(c),\n  chain\u003cB\u003e(r: (a: A) =\u003e Reader\u003cC, B\u003e) {\n    return reader\u003cC, B\u003e(c =\u003e {\n      const [_, a] = this.addConfig(c);\n      return r(a).addConfig(c);\n    });\n  },\n  map\u003cB\u003e(f: (a: A) =\u003e B) {\n    return reader\u003cC, B\u003e(c =\u003e {\n      const [_, a] = this.addConfig(c);\n      return [c, f(a)];\n    });\n  }\n});\n```\n\nAs we can see, in the `chain` method, I'm ignoring the config that cames from the first Reader (`[_, a]`), and using the first one. That way, even if the user changes the config by mistake, we stick with the original.\n\nAnd, of course, our super contrived example:\n\n```typescript\nconst config = { env: \"development\" };\ntype Config = typeof config;\nconst withConfig = (c: Config): [Config, number] =\u003e [\n  c,\n  c.env === \"development\" ? 10 : 0\n];\nconst f = (x: number) =\u003e x * 10;\nconst g = (x: number) =\u003e x - 10;\n\nreader\u003cConfig, number\u003e(withConfig)\n  .map(f)\n  .map(g)\n  .addConfig(config);\n\n// env === 'development' -\u003e 10 -\u003e 100 -\u003e 90\n```\n\n## Pattern Matching\n\nI was researching about pattern matching and found an incredible [article](https://medium.com/swlh/pattern-matching-in-typescript-with-record-and-wildcard-patterns-6097dd4e471d) and [lib](https://github.com/WimJongeneel/ts-pattern-matching) written by Wim Jongeneel.\n\nHe uses a lot of TS features that are new to me. Here another cool [article](https://dev.to/aexol/typescript-tutorial-infer-keyword-2cn) from Artur Czemiel explaining the `infer` and conditional types.\n\nWith that, I rewrote the Either to use pattern matching:\n\n```typescript\nype EitherValue\u003cL, R\u003e = { tag: \"left\"; value: L } | { tag: \"right\"; value: R };\n\nexport interface Right\u003cL, R\u003e {\n  map: \u003cB\u003e(f: (x: R) =\u003e B) =\u003e Right\u003cL, B\u003e;\n  chain: \u003cB\u003e(f: (x: R) =\u003e Right\u003cL, B\u003e) =\u003e Right\u003cL, B\u003e;\n  fold: \u003cB, C\u003e(onLeft: (x: L) =\u003e B, onRight: (x: R) =\u003e C) =\u003e B | C;\n  inspect: () =\u003e string;\n}\n\nexport interface Left\u003cL, R\u003e {\n  map: \u003cB\u003e(f: (x: R) =\u003e B) =\u003e Left\u003cL, B\u003e;\n  chain: \u003cB\u003e(f: (x: R) =\u003e Left\u003cL, B\u003e) =\u003e Left\u003cL, B\u003e;\n  fold: \u003cB, C\u003e(onLeft: (x: L) =\u003e B, onRight: (x: R) =\u003e C) =\u003e B | C;\n  inspect: () =\u003e string;\n}\n\nconst right = \u003cL, R\u003e(value: R): Right\u003cL, R\u003e =\u003e ({\n  map: \u003cB\u003e(f: (x: R) =\u003e B) =\u003e right\u003cL, B\u003e(f(value)),\n  chain: \u003cB\u003e(f: (x: R) =\u003e Right\u003cL, B\u003e) =\u003e f(value),\n  fold: \u003cB, C\u003e(onLeft: (x: L) =\u003e B, onRight: (x: R) =\u003e C) =\u003e onRight(value),\n  inspect: () =\u003e `Right(${value})`\n});\n\nconst left = \u003cL, R\u003e(value: L): Left\u003cL, R\u003e =\u003e ({\n  map: \u003cB\u003e(_: (x: R) =\u003e B) =\u003e left\u003cL, B\u003e(value),\n  chain: \u003cB\u003e(_: (x: R) =\u003e Right\u003cL, B\u003e) =\u003e left\u003cL, B\u003e(value),\n  fold: \u003cB, C\u003e(onLeft: (x: L) =\u003e B, onRight: (x: R) =\u003e C) =\u003e onLeft(value),\n  inspect: () =\u003e `Left(${value})`\n});\n\nexport type Either\u003cL, R\u003e = Right\u003cL, R\u003e | Left\u003cL, R\u003e;\n\nexport const either = \u003cL, R\u003e(\n  taggedValue: EitherValue\u003cL, R\u003e\n): Left\u003cL, R\u003e | Right\u003cL, R\u003e =\u003e\n  match\u003cEitherValue\u003cL, R\u003e, Right\u003cL, R\u003e | Left\u003cL, R\u003e\u003e(taggedValue)\n    .with({ tag: \"left\" }, ({ tag, value }) =\u003e left\u003cL, R\u003e(value))\n    .with({ tag: \"right\" }, ({ tag, value }) =\u003e right\u003cL, R\u003e(value))\n    .run();\n```\n\nThere still a ton to TS stuff I need to learn. Conditional typing can improve our sum types, so stay tuned for more refactor soon.\n\n## Work in progress\n\nThis repo is a journal of my learning process though the land of Functional Programing and TypeScript.\nAll help is welcome, so feel free to propose code improvements, fixes, and more material to learn.\n\n## Contributing\n\n1. Fork it!\n2. Create your feature branch: git checkout -b my-new-feature\n3. Commit your changes: git commit -am 'Add some feature'\n4. Push to the branch: git push origin my-new-feature\n5. Submit a pull request :D\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2020 Rafael Campos\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frafbcampos%2Fnaive_functional_programming","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frafbcampos%2Fnaive_functional_programming","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frafbcampos%2Fnaive_functional_programming/lists"}