{"id":32117213,"url":"https://github.com/identinet/sanctuary-cheat-sheet","last_synced_at":"2026-05-13T20:34:50.659Z","repository":{"id":62422170,"uuid":"376910081","full_name":"identinet/sanctuary-cheat-sheet","owner":"identinet","description":"Functional programming cheat sheet for https://sanctuary.js.org/","archived":false,"fork":false,"pushed_at":"2023-11-10T10:37:52.000Z","size":46,"stargazers_count":23,"open_issues_count":2,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-03-30T15:36:22.338Z","etag":null,"topics":["cheatsheet","examples","fantasy-land","functional-programming","javascript","sanctuary"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/identinet.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,"roadmap":null,"authors":null}},"created_at":"2021-06-14T17:49:35.000Z","updated_at":"2025-12-02T02:11:46.000Z","dependencies_parsed_at":"2024-01-13T07:23:20.323Z","dependency_job_id":"9b2145c0-17e0-42af-933e-dd399ab3adc2","html_url":"https://github.com/identinet/sanctuary-cheat-sheet","commit_stats":{"total_commits":61,"total_committers":2,"mean_commits":30.5,"dds":"0.11475409836065575","last_synced_commit":"ac8cd8bed887cb592770052ad3469154fc1a51d4"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/identinet/sanctuary-cheat-sheet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/identinet%2Fsanctuary-cheat-sheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/identinet%2Fsanctuary-cheat-sheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/identinet%2Fsanctuary-cheat-sheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/identinet%2Fsanctuary-cheat-sheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/identinet","download_url":"https://codeload.github.com/identinet/sanctuary-cheat-sheet/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/identinet%2Fsanctuary-cheat-sheet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32999515,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"ssl_error","status_checked_at":"2026-05-13T13:14:51.610Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["cheatsheet","examples","fantasy-land","functional-programming","javascript","sanctuary"],"created_at":"2025-10-20T16:29:59.671Z","updated_at":"2026-05-13T20:34:50.646Z","avatar_url":"https://github.com/identinet.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Work in Progress](https://img.shields.io/badge/WIP-Work%20in%20Progress-yellow)\n\n# Sanctuary Cheat Sheet\n\nThe goal of this cheat sheet is to make it easy for newcomers and experienced\ndevelopers to work with the [Sanctuary library][sanctuary] by describing common\npatterns and best practices.\n\nWARNING: the information in this cheat sheet is by no means a comprehensive\ncollection of all the library functions and types. Nor are the examples the only\nor even the best way of how to use them in your code. Keep this in mind and also\ndive into\n[other resources](#resources---additional-things-that-might-be-helpful). I\nhighly recommend reading\n[Things I wish someone had explained about Functional Programming](https://jrsinclair.com/articles/2019/what-i-wish-someone-had-explained-about-functional-programming/)\nand the\n[Fantas, Eel, and Specification](http://www.tomharding.me/fantasy-land/).\n\n\u003c!-- Table of Contents generated with:\n!deno run --unstable --allow-read --allow-write https://deno.land/x/remark_format_cli@v0.1.0/remark-format.js %\n--\u003e\n\n## Contents\n\n1. [Read-Eval-Print-Loop - try out Sanctuary](#read-eval-print-loop---try-out-sanctuary)\n   1. [Web](#web)\n   2. [Local browser](#local-browser)\n   3. [Deno](#deno)\n2. [Function definition](#function-definition)\n   1. [Define parameters](#define-parameters)\n   2. [Define processing steps](#define-processing-steps)\n   3. [Define function signature with types](#define-function-signature-with-types)\n3. [Type definition - create your own functional types](#type-definition---create-your-own-functional-types)\n4. [Piping - connecting function outputs to function inputs and avoid intermediate variables](#piping---connecting-function-outputs-to-function-inputs-and-avoid-intermediate-variables)\n5. [Print debugging - inspecting intermediate values](#print-debugging---inspecting-intermediate-values)\n6. [Branching - handling if-else cases](#branching---handling-if-else-cases)\n7. [Promises - back to the Future](#promises---back-to-the-future)\n   1. [Integration with Sanctuary](#integration-with-sanctuary)\n   2. [Basic setup](#basic-setup)\n   3. [Promises - working with Promise-returning functions](#promises---working-with-promise-returning-functions)\n   4. [Processing - the Future is yet to come](#processing---the-future-is-yet-to-come)\n   5. [Parallel Futures](#parallel-futures)\n   6. [Stopping the Future](#stopping-the-future)\n8. [map or chain?](#map-or-chain)\n   1. [map - transform a list of values](#map---transform-a-list-of-values)\n   2. [chain - perform type-aware transformation of values](#chain---perform-type-aware-transformation-of-values)\n   3. [join - combine multiple objects of the same type](#join---combine-multiple-objects-of-the-same-type)\n9. [filter - remove unneeded values](#filter---remove-unneeded-values)\n10. [reduce - accumulate values](#reduce---accumulate-values)\n11. [Error handling](#error-handling)\n    1. [Maybe - the better null/NaN/undefined return value](#maybe---the-better-nullnanundefined-return-value)\n    2. [Either - the better alternative to throw Error](#either---the-better-alternative-to-throw-error)\n    3. [bimap - mapping over two values (potential failure)](#bimap---mapping-over-two-values-potential-failure)\n12. [Pair - storing key-value pairs](#pair---storing-key-value-pairs)\n13. [Libraries - little helpers](#libraries---little-helpers)\n14. [Resources - additional things that might be helpful](#resources---additional-things-that-might-be-helpful)\n    1. [Sanctuary](#sanctuary)\n    2. [Fantasy Land Spec / Theory](#fantasy-land-spec--theory)\n    3. [Video Tutorials](#video-tutorials)\n    4. [Books](#books)\n    5. [Miscellaneous](#miscellaneous)\n\n## Read-Eval-Print-Loop - try out Sanctuary\n\n### Web\n\nA web-based [Sanctuary][sanctuary]-only REPL is available\n[online](https://sanctuary.js.org/#section:overview), start typing in the\n\u003cspan style=\"color: green;\"\u003egreen\u003c/span\u003e box.\n\n### Local browser\n\nTo quickly get a local [Sanctuary][sanctuary] and [Fluture][fluture] REPL, open\nthe developer tools in your browser (keyboard shortcut `Ctrl-Shift-i`) and\nexecute this instruction:\n\n```javascipt\nlet S; let def; let F;\nimport(\"https://deno.land/x/sanctuary_cheat_sheet@v0.0.4/repl.js\").then(l =\u003e {S = l.S; def = l.def; F = l.F;});\n```\n\n### Deno\n\nTo quickly get a local [Sanctuary][sanctuary] and [Fluture][fluture] REPL, run\nthis command:\n\n```bash\ndeno repl --eval 'import {S, def, F} from \"https://deno.land/x/sanctuary_cheat_sheet@v0.0.4/repl.js\"'\n```\n\n## Function definition\n\nThere are three aspects to defining functions:\n\n1. Define the parameters - one after the other\n2. Define the processing steps\n3. Define the function signature with types\n\n### Define parameters\n\nIn functional programming functions are usually curried. This means that a\nfunction only takes one parameter. If a function requires more than one\nparameter it should be defined as a function that takes one parameter and\nreturns a functional that requires another parameter.\n\nFortunately, JavaScript's arrow functions make it really easy to create curried\nfunctions:\n\n```javascript\nconst myfunction = (parameter1) =\u003e (parameter2) =\u003e (parameter3) =\u003e {\n  // the function body\n};\n```\n\n### Define processing steps\n\nIn sanctuary there's a convenient way of defining the processing steps - the\n[`pipe`][pipe] function. [`pipe`][pipe] takes a list of functions and it passes\nthe output value of one function as the input value into the following function.\nSee\n[Piping](#piping---connecting-function-outputs-to-function-inputs-and-avoid-intermediate-variables)\nfor more information:\n\n```javascript\nconst myfunction = (parameter1) =\u003e\n  S.pipe([\n    // first processing step\n    doA,\n    // second processing step\n    doB,\n    // ...\n    doC,\n  ])(parameter1);\n```\n\n### Define function signature with types\n\nFor very simple functions defining processing steps might be enough. However, to\nget all the benefits from sanctuary's type checking functionality the function\nsignature needs to be defined the sanctuary way. Take a look at the\n[built-in types](https://github.com/sanctuary-js/sanctuary-def#types):\n\n```javascript\n// define a def function that makes it easy to create functions with\ntype checks\nconst $ = require(\"sanctuary-def\");\nconst def = $.create({\n  checkTypes: process.env.NODE_ENV === \"development\",\n  env,\n});\n\n//    add :: Number -\u003e Number -\u003e Number\nconst add =\ndef ('add')                           // name\n    ({})                              // type-class constraints\n    ([$.Number, $.Number, $.Number])  // input and output types\n    (x =\u003e y =\u003e x + y);                // implementation\n```\n\nTODO daggy\n\n## Type definition - create your own functional types\n\nThe types that can be used by functions need to be first defined. Sanctuary has\na number of constructors for defining types. Take a look at sanctuary's\n[Type constructors](https://github.com/sanctuary-js/sanctuary-def#type-constructors).\nHere is a very simple one that defines an integer. Keep in mind that a\ndocumentation URL is required where more information can be found about the\ntype - the project's `REAMDE.md` is a good place to keep the type definition\ndocumentation at:\n\n```javascript\nconst Integer = $.NullaryType(\n  // name\n  \"Integer\",\n)(\n  // documentation URL\n  \"http://example.com/my-package#Integer\",\n)(\n  // supertypes\n  [],\n)(\n  // predicate values need to satisfy\n  (x) =\u003e\n    typeof x === \"number\" \u0026\u0026\n    Math.floor(x) === x \u0026\u0026\n    x \u003e= Number.MIN_SAFE_INTEGER \u0026\u0026\n    x \u003c= Number.MAX_SAFE_INTEGER,\n);\n```\n\n## Piping - connecting function outputs to function inputs and avoid intermediate variables\n\nFunctions often contain a lot of calls to other functions. The intermediate\nvalues of the function calls are stored in variables are passed again to other\nfunction calls. It might look something like this:\n\n```javascript\nconst myfunction = (parameter1) =\u003e (parameter2) =\u003e (parameter3) =\u003e {\n  const resA = doA(parameter1);\n  const resB = doB(parameter2)(resA);\n  const resC = doC(parameter3)(resB);\n  return resC;\n};\n```\n\nThis could be optimized with the [`pipe`][pipe] function by removing the\nvariables and feeding the intermediate results directly into the next function:\n\n```javascript\nconst myfunction = (parameter1) =\u003e (parameter2) =\u003e (parameter3) =\u003e\n  S.pipe([\n    doA,\n    // output of doA is piped as input into doB\n    doB(parameter2),\n    doC(parameter3),\n  ])(parameter1);\n```\n\n## Print debugging - inspecting intermediate values\n\nThe goal of print debugging is to peek into a function execution chain and learn\nabout intermediate results.\n\nExample, given the following function - how to inspect the return value of\n`doA`?\n\n```javascript\nconst myfunction = S.pipe([\n  // some function calls\n  doA,\n  doB,\n  doC,\n]);\n```\n\nSolution, define a `log` function that prints a message and the received value\nand returns the value. Then add the `log` function between `doA` and `doB`:\n\n```javascript\nconst log = (msg) =\u003e (value) =\u003e {\n  console.log(msg, value);\n  return value;\n};\n\nconst myfunction = S.pipe([\n  doA,\n  // insert log function\n  log(\"Return value of do3:\"),\n  doB,\n  doC,\n]);\n```\n\n## Branching - handling if-else cases\n\nIn a function there is often the need to handle two cases differently:\n\n```javascript\nconst myfunction = (parameter1) =\u003e {\n  const res = computeSomething(parameter1);\n  if (res \u003e 0) {\n    doA(res);\n  } else {\n    doB(res);\n  }\n  // further processing\n};\n```\n\nIn [Sanctuary][sanctuary] it could be done with the [`ifElse`][ifelse] function\nas follows:\n\n```javascript\nconst myfunction = (parameter1) =\u003e\n  S.pipe([\n    computeSomething,\n    S.ifElse((res) =\u003e res \u003e 0)(doA)(doB),\n    // further processing\n  ])(parameter1);\n```\n\nThis could get ugly if there are more cases that need to be distinguished, e.g.\n`res \u003c 0`, `res \u003c 10` and `res \u003e= 10`:\n\n```javascript\nconst myfunction = (parameter1) =\u003e\n  S.pipe([\n    computeSomething,\n    S.ifElse((res) =\u003e res \u003c 0)(doB)(S.ifElse((res) =\u003e res \u003c 10)(doA))(doC),\n  ])(parameter1);\n```\n\nIn this case it might be easier to TODO ...?\n\n## Promises - back to the Future\n\n[Sanctuary][sanctuary] doesn't provide special handling for\n[`Promises`][promise]. However, since they're used all over the place in\nJavaScript it would be great to deal with them in a functional way. There's a\nfunctional [`Promises`][promise] library for this:\n[Fluture](https://github.com/fluture-js/Fluture)\n\n### Integration with Sanctuary\n\nHere's the official\n[Fluture sanctuary integration](https://github.com/fluture-js/Fluture#sanctuary).\nThe important lines are:\n\n```javascript\nimport sanctuary from \"sanctuary\";\nimport { env as flutureEnv } from \"fluture-sanctuary-types\";\nconst S = sanctuary.create({\n  checkTypes: true,\n  env: sanctuary.env.concat(flutureEnv),\n});\nimport { attemptP, encaseP, fork, parallel } from \"Fluture\";\n```\n\n### Basic setup\n\nThe [`fork`][fork] call needs to be present in the program and there should be\nideally _only one_ fork call. [`fork`][fork] processes the [`Promise`][promise].\nWithout [`fork`][fork] no processing of [`Futures`][future] takes place.\n\n```javascript\nfork(\n  // error case\n  log(\"rejection\"),\n)(\n  // resolution case\n  log(\"resolution\"),\n)(attemptP(() =\u003e Promise.resolve(42)));\n```\n\n### Promises - working with Promise-returning functions\n\nThere are two main helper functions by Fluture to deal with\n[`Promises`][promise]: [`attemptP`][attemptp] and [`encaseP`][encasep].\n\n[`attemptP`][attemptp] takes a function that doesn't take a parameter and turns\nit into a [`Future`][future], e.g.:\n\n```javascript\nattemptP(() =\u003e Promise.resolve(42));\n```\n\n[`encaseP`][encasep] takes a function that takes one parameter and turns it into\na [`Future`][future], e.g.:\n\n```javascript\nencaseP(fetch)(\"https://api.github.com/users/Avaq\");\n```\n\n### Processing - the Future is yet to come\n\nThe main question is how do we deal with Futures in [`pipe`][pipe]. There are\ntwo important cases to keep in mind: [map or chain?](#map-or-chain). Either we\nprocess the Future with [`map`][map] (2) - in this case no knowledge about the\nFuture is required by the function that receives the value - or with\n[`chain`][chain] (3) - in this case the Future is consumed and a new future needs to\nbe returned by the function.\n\nIf we forget to use [`map`][map] or [`chain`][chain] in a function call (1), the\nfunction receives the unfinished Future. It's like acting on a\n[`Promise`][promise] without calling `.then()` or `await` on it.\n\n```javascript\nconst myfunction = S.pipe([\n  encaseP(fetch),\n  log(\"Try to log the output of fetch:\"), // 1\n  S.map(log(\"Log the output of fetch:\")), // 2\n  S.map(extractURL),\n  S.chain(encaseP(fetch)), // 3\n]);\n\nfork(log(\"rejection\"))(log(\"resolution\"))(\n  myfunction(\"https://api.github.com/users/Avaq\"),\n);\n```\n\n### Parallel Futures\n\nIt's also possible to process multiple [`Futures`][future] in a functional way.\nFor example, multiple long-running computations should to be performed.\n[`parallel`][parallel] provides this functionality and controls the number of\nparallel executions with the first parameter:\n\n```javascript\nconst myLongRunningFunction = (x) =\u003e {\n  // computation take 1 sec\n  return new Promise((resolve, reject) =\u003e setTimeout(resolve, 1000, x * 2));\n};\n\nfork(log(\"rejection\"))(log(\"resolution\"))(\n  S.pipe([\n    // 5 Futures are created\n    S.map(encaseP(myLongRunningFunction)),\n    // 2 Futures are processed in parallel until all are resolved\n    parallel(2),\n  ])([1, 2, 3, 4, 5]),\n);\n```\n\n### Stopping the Future\n\nUnlike [`Promises`][promise], [`Futures`][future] don't execute the contained\nfunction unless [`fork`][fork] is called on it. This makes it possible to stop a\n[`Future`][future] or to never execute it if not needed. The functionality is\ndescribed in detail in the [Cancellation documentation][cancellation].\n\n## map or chain?\n\nThere are these two different functions, [`map`][map] and [`chain`][chain], that\nlook very similar. However, using one over the other is sometimes advantageous.\n\n### map - transform a list of values\n\n[`map`][map] is defined by the [`Functor` class type][functor]. Every\n[`Functor`][functor] implements [`map`][map]. [`Functors`][functor] are often\narrays and [`map`][map] maps a function over every element of the array.\nExample, add `1` to every element in an array of numbers:\n\n```javascript\nconst numbers = [1, 2, 3];\nconst add = (number1) =\u003e (number2) =\u003e number1 + number2;\nS.map(add(1))(numbers);\n\n// result: [2, 3, 4]\n```\n\nIn addition, something like a [`Pair`][pair] or a [`Promise`][promise] could\nalso be a [`Functor`][functor]. In this case [`map`][map] maps over the value,\ne.g. the result of a [`Promise`][promise] or the value of a [`Pair`][pair].\n\n```javascript\nconst pair = S.Pair(\"a\")(1);\nconst add = (number1) =\u003e (number2) =\u003e number1 + number2;\nS.map(add(1))(pair);\n\n// result: Pair (\"a\") (2)\n```\n\nAs you can see in the example, the `add` doesn't concern itself with the inner\nworkings of the data type but just operates on the value. [`map`][map] does the\nheavy lifting of getting the [`Functors`][functor] value out and wrapping the\nmodified value back in a [`Functor`][functor]. This is very convenient because\nit makes functions easily applicable to all kinds of [`Functors`][functor].\n\n### chain - perform type-aware transformation of values\n\nHowever, sometimes this is intelligence of putting the returned value back in a\n[`Functor`][functor] works against us. For example, we want to parse an integer\nfrom string but only want to return a [`Just`][just] value if the integer is\ngreater than 10 otherwise [`Nothing`][nothing]. If we tried to do this with\n[`map`][map] we'd end up with this result:\n\n```javascript\nS.pipe([\n  S.parseInt(10),\n  S.map(S.ifElse((v) =\u003e v \u003e 10)(S.Just)((v) =\u003e S.Nothing)),\n])(\"100\");\n\n// result: Just (Just (100))\n```\n\nThere are now two nested [`Just`][just] data types. As you can see from the\nimplementation, the function that's called by [`map`][map]already uses the\ncomplex data type [`Pair`][pair] (implemented by [`Just`][just] and\n[`Nothing`][nothing]). Therefore, if since we pass a [`Pair`][pair] into the\nfunction and the function returns a [`Pair`][pair], we don't need[`map`][map]'s\nfeature of wrapping the returned value in the passed in [`Functor`][functor].\n[`chain`][chain] as defined by the Chain class type does exactly that, it\nexpects the function to properly wrap the return value in the\n[`Functor`][functor]. This is important when working with [`Promises`][promise]\nto ensure that we're not wrapping an unresolved [`Promise`][promise] inside a\nresolved [`Promise`][promise] but return the unresolved [`Promise`][promise] so\nwe can wait for its completion:\n\n```javascript\nS.pipe([\n  S.parseInt(10),\n  S.chain(S.ifElse((v) =\u003e v \u003e 10)(S.Just)((v) =\u003e S.Nothing)),\n])(\"100\");\n\n// result: Just (100)\n```\n\n### join - combine multiple objects of the same type\n\nIf you receive a value that's wrapped twice in the same type we can use\n[`join`][join] to remove one layer of wrapping:\n\n```javascript\nS.pipe([\n  S.parseInt(10),\n  S.map(S.ifElse((v) =\u003e v \u003e 10)(S.Just)((v) =\u003e S.Nothing)),\n  S.join, // added join\n])(\"100\");\n\n// result: Just (100)\n```\n\nNote that the added [`join`][join] plays nicely in case [`Nothing`][nothing] is\nreturned by [`parseInt`][parseint]:\n\n```javascript\nS.pipe([\n  S.parseInt(10),\n  S.map(S.ifElse((v) =\u003e v \u003e 10)(S.Just)((v) =\u003e S.Nothing)),\n  S.join, // added join\n])(\"invalid100\");\n\n// result: Nothing\n```\n\n## filter - remove unneeded values\n\nWhen composing function calls with [`pipe`][pipe] it's common that arrays of\nvalues are processed. [`map`][map] is great for transforming array elements with\nthe help of other functions. However, sometimes the list of array elements needs\nto be reduced before processing them further. For example, `null` values or\n[`Nothing`][nothing] values need to be removed or numbers that are lower than a\ncertain threshold. This can be easily done with [`filter`][filter] that takes a\npredicate / filter function:\n\n```javascript\nS.filter(\n  // predicate function that's applied to input values\n  (x) =\u003e x \u003e 3,\n)(\n  // the input values\n  [1, 2, 3, 4, 5],\n);\n\n// [ 4, 5 ]\n```\n\n## reduce - accumulate values\n\nIn the same way as [`filter`][filter], [`reduce`][reduce] operates on an array\nof values and transforms + collects them into an accumulated/reduced new value.\nThis concept of reducing values is so powerful that [`map`][map] and\n[`filter`][filter] can be expressed with [`reduce`][reduce]. However, expressing\n[`map`][map] or [`filter`][filter] via [`reduce`][reduce] is more difficult to\nread than using the predefined functions. Therefore, we'll stick to simple\nreduction feature here. For example, the values of an array could be summed up\nwith [`reduce`][reduce]:\n\n```javascript\nS.reduce(\n  // function that performs the accumulation / reduction of values\n  (acc) =\u003e (x) =\u003e acc + x,\n)(\n  // start value for acc\n  0,\n)(\n  // the input values\n  [1, 2, 3, 4, 5],\n);\n\n// result: 15\n```\n\n## Error handling\n\nWhen processing data sometimes the data doesn't conform to the requirements and\nan error is raised. In [Sanctuary][sanctuary] there are multiple ways of\nhandling errors, a few of them are explored here:\n\n### Maybe - the better null/NaN/undefined return value\n\nA function might not be able to operate on all possible input values. For\nexample, the [`parseInt`][parseint] function takes a string and tries to parse\nan integer from it. When it fails to parse the string the function could return\n[`null`][null], [`undefined`][undefined] or [`NaN`][nan] but this leaves lots of\nroom for interpretation as it's not clear whether the function was able to\nprocess the input properly.\n\nInstead, a [`Maybe`][maybe] type could be returned that wraps the actual result\nin either a [`Just`][just] or a [`Nothing`][nothing] object. When wrapping the\nreturn value in a [`Maybe`][maybe] object further processing steps graciously\ndeal with the result. For example, [`map`][map] only executes the transformation\nfunction when a [`Just`][just] object is returned:\n\n```javascript\nconst myParseInt = (str) =\u003e {\n  const res = parseInt(str);\n  if (isNaN(res)) {\n    return S.Nothing;\n  }\n  return S.Just(res);\n};\n\nS.show(\n  S.map(\n    S.pipe([\n      // call to function that produces a Maybe result object\n      myParseInt,\n      // further processing\n      S.map((x) =\u003e x + 10),\n    ]),\n  )([\"1\", \"invalid1\"]),\n);\n\n// result: [Just (11), Nothing]\n```\n\nAdditional [functions][maybe] exist for handling [`Maybe`][maybe] objects.\n\n### Either - the better alternative to throw Error\n\nAnother programming challenge is to deal with errors, for example when an\nattempted division by zero. Instead of [`throwing`][throw] an [`Error`][error],\n[Sanctuary][sanctuary] offers the [`Either`][either] type that can be a\n[`Right`][right] object that includes the successful result or a [`Left`][left]\nobject that includes the error.\n\n[`Either`][either] is different from [`Maybe`][maybe] in that [`Left`][left]\ncontains additional data for processing and potentially recovering from the\nerror while [`Nothing`][nothing] contains no data.\n\n```javascript\nconst myDiv = (num) =\u003e (divider) =\u003e {\n  if (divider === 0) {\n    return S.Left(\"Division by zero.\");\n  }\n  return S.Right(num / divider);\n};\n\nS.show(\n  S.map(\n    S.pipe([\n      // call to function that produces an Either result object\n      myDiv(25),\n      // further processing\n      S.map((x) =\u003e x + 10),\n    ]),\n  )([5, 0]),\n);\n\n// result: [Right (15), Left (\"Division by zero.\")]\n```\n\nAdditional [functions][either] exist for handling [`Either`][either] objects.\n\n### bimap - mapping over two values (potential failure)\n\nWhen there are multiple subtypes to deal with like [`Left`][left] and\n[`Right`][right] it would be handy to be able to map over both options.\n[`bimap`][bimap] provides this feature so we can begin handling the failure:\n\n```javascript\nconst myDiv = (num) =\u003e (divider) =\u003e {\n  if (divider === 0) {\n    return S.Left(\"Division by zero.\");\n  }\n  return S.Right(num / divider);\n};\n\nS.show(\n  S.map(\n    S.pipe([\n      // call to function that produces an Either result object\n      myDiv(25),\n      // further processing\n      S.bimap(S.toUpper)((x) =\u003e x + 10),\n    ]),\n  )([5, 0]),\n);\n\n// result: [Right (15), Left (\"DIVISION BY ZERO.\")]\n```\n\n[`mapLeft`][mapleft] is another option for just interacting with the error case.\nFor [`Futures`][future], [`coalesce`][coalesce] and [`mapRej`][maprej] are the\nrespective functions for dealing with rejected values.\n\n## Pair - storing key-value pairs\n\n[Sanctuary][sanctuary] provides the type [`Pair`][pair] for storing key-value\npairs. Compared to a simple JavaScript [`Object`][object] (`{}`), [`Pair`][pair]\nplays nicely with other functions, e.g. [`map`][map] and [`mapLeft`][mapleft]:\n\n```javascipt\nconst p = S.Pair('balance')(1)\n\nS.show(S.map(x =\u003e x * 2)(p))\n// result: Pair (\"balance\") (2)\n\nS.show(S.mapLeft(x =\u003e \"accountnumber\")(p))\n// result: Pair (\"accountnumber\") (1)\n```\n\n## Libraries - little helpers\n\n- Sanctuary - Refuge from unsafe JavaScript: [Sanctuary][sanctuary]\n- Sanctuary type class overview:\n  [Sanctuary Type Classes](https://github.com/sanctuary-js/sanctuary-type-classes)\n  and [Fantasy Land Specification](https://github.com/fantasyland/fantasy-land)\n- Sanctuary type overview:\n  [sanctuary-def](https://github.com/sanctuary-js/sanctuary-def)\n- Fluture - Fantasy Land compliant (monadic) alternative to Promises:\n  [Fluture](https://github.com/fluture-js/Fluture)\n- Most - Monadic stream for reactive programming:\n  [Most](https://github.com/cujojs/most)\n\n## Resources - additional things that might be helpful\n\n### Sanctuary\n\n- Sanctuary library introduction:\n  [Sanctuary, Programming Safely in an Uncertain World](https://www.youtube.com/watch?v=a2astdDbOjk)\n- Sanctuary Abstract Data Type Overview:\n  [Sanctuary ADT Matrix](https://github.com/dotnetCarpenter/sanctuary-adt-matrix)\n\n### Fantasy Land Spec\n\n- Introduction to functional programming:\n  [Things I wish someone had explained about Functional Programming](https://jrsinclair.com/articles/2019/what-i-wish-someone-had-explained-about-functional-programming/)\n  1. [Algebraic structures](https://jrsinclair.com/articles/2019/algebraic-structures-what-i-wish-someone-had-explained-about-functional-programming/)\n  2. [Type classes](https://jrsinclair.com/articles/2019/type-classes-what-i-wish-someone-had-explained-about-functional-programming/)\n  3. [Algebraic data types](https://jrsinclair.com/articles/2019/algebraic-data-types-what-i-wish-someone-had-explained-about-functional-programming/)\n- Fantasy Land Spec walk through:\n  [Fantas, Eel, and Specification](http://www.tomharding.me/fantasy-land/)\n  1. [Daggy](http://www.tomharding.me/2017/03/03/fantas-eel-and-specification/)\n  2. [Type Signatures](http://www.tomharding.me/2017/03/08/fantas-eel-and-specification-2/)\n  3. [Setoid](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-3/)\n  4. [Ord](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-3.5/)\n  5. [Semigroup](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-4/)\n  6. [Monoid](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-5/)\n  7. [Functor](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-6/)\n  8. [Contravariant](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-7/)\n  9. [Apply](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-8/)\n  10. [Applicative](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-9/)\n  11. [Alt, Plus, and Alternative](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-10/)\n  12. [Foldable](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-11/)\n  13. [Traversable](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-12/)\n  14. [Chain](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-13/)\n  15. [ChainRec](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-14/)\n  16. [Monad](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-15/)\n  17. [Extend](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-16/)\n  18. [Comonad](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-17/)\n  19. [Bifunctor and Profunctor](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-18/)\n  20. [Semigroupoid and Category](http://www.tomharding.me/2017/03/09/fantas-eel-and-specification-19/)\n\n### Video Tutorials\n\n- Functional programming video tutorial series:\n  [Professor Frisby Introduces Composable Functional JavaScript](https://egghead.io/lessons/javascript-you-ve-been-using-monads)\n- Functional Design Patterns:\n  [Functional Design Patterns - Scott Wlashin](https://www.youtube.com/watch?v=ucnWLfBA1dc)\n- Functional programming pattern Monad explained in 100sec:\n  [What is a Monad?](https://www.youtube.com/watch?v=VgA4wCaxp-Q)\n- Functional Domain Modeling:\n  [Domain Modeling Made Functional - Scott Wlashin](https://www.youtube.com/watch?v=Up7LcbGZFuo)\n- JavaScript Functional Programming YouTube Channel:\n  [Fun Fun Function](https://www.youtube.com/channel/UCO1cgjhGzsSYb1rsB4bFe4Q)\n\n### Books\n\n- [Prof. Frisby's Mostly Adequate Guide to Functional Programming](https://github.com/MostlyAdequate/mostly-adequate-guide)\n- [Composing Software](https://medium.com/javascript-scene/composing-software-the-book-f31c77fc3ddc)\n- [Functional-Light JavaScript](https://github.com/getify/functional-light-js)\n- [Category Theory for Programmers](https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/)\n\n### Miscellaneous\n\n- Awesome List Functional Programming in JavaScript:\n  [Awsome FP JS](https://github.com/stoeffel/awesome-fp-js)\n\n[attemptp]: https://github.com/fluture-js/Fluture#attemptp\n[bimap]: https://sanctuary.js.org/#bimap\n[cancellation]: https://github.com/fluture-js/Fluture#cancellation\n[chain]: https://sanctuary.js.org/#chain\n[coalesce]: https://github.com/fluture-js/Fluture#coalesce\n[either]: https://sanctuary.js.org/#Either\n[encasep]: https://github.com/fluture-js/Fluture#encaseP\n[error]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error\n[filter]: https://sanctuary.js.org/#filter\n[fork]: https://github.com/fluture-js/Fluture#fork\n[functor]: https://github.com/sanctuary-js/sanctuary-type-classes#type-class-hierarchy\n[fluture]: https://github.com/fluture-js/Fluture\n[future]: https://github.com/fluture-js/Fluture#future\n[ifelse]: https://sanctuary.js.org/#ifElse\n[join]: https://sanctuary.js.org/#join\n[just]: https://sanctuary.js.org/#Just\n[left]: https://sanctuary.js.org/#Left\n[maprej]: https://github.com/fluture-js/Fluture#mapRej\n[map]: https://sanctuary.js.org/#map\n[mapleft]: https://sanctuary.js.org/#mapLeft\n[maybe]: https://sanctuary.js.org/#Maybe\n[nan]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN\n[nothing]: https://sanctuary.js.org/#Nothing\n[null]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null\n[pair]: https://sanctuary.js.org/#section:pair\n[parallel]: https://github.com/fluture-js/Fluture#parallel\n[parseint]: https://sanctuary.js.org/#parseInt\n[pipe]: https://sanctuary.js.org/#pipe\n[promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise\n[reduce]: https://sanctuary.js.org/#reduce\n[right]: https://sanctuary.js.org/#Right\n[sanctuary]: https://sanctuary.js.org/\n[throw]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw\n[undefined]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined\n[object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fidentinet%2Fsanctuary-cheat-sheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fidentinet%2Fsanctuary-cheat-sheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fidentinet%2Fsanctuary-cheat-sheet/lists"}