{"id":30348925,"url":"https://github.com/sash-ua/monad-ts","last_synced_at":"2025-08-18T19:17:10.126Z","repository":{"id":57301381,"uuid":"90028120","full_name":"sash-ua/monad-ts","owner":"sash-ua","description":"Monad-ts is a small library implements some of key monads and way to chain them in a flow (pipe) in JavaScript and TypeScript.","archived":false,"fork":false,"pushed_at":"2018-06-22T19:58:17.000Z","size":1126,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-09T11:21:05.500Z","etag":null,"topics":["functional-js","functional-programming","monad-library","monad-ts","monads","store","typescript","typescript-library"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sash-ua.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-05-02T11:53:46.000Z","updated_at":"2018-09-06T14:53:11.000Z","dependencies_parsed_at":"2022-08-24T17:11:45.365Z","dependency_job_id":null,"html_url":"https://github.com/sash-ua/monad-ts","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sash-ua/monad-ts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sash-ua%2Fmonad-ts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sash-ua%2Fmonad-ts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sash-ua%2Fmonad-ts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sash-ua%2Fmonad-ts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sash-ua","download_url":"https://codeload.github.com/sash-ua/monad-ts/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sash-ua%2Fmonad-ts/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269749012,"owners_count":24469279,"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","status":"online","status_checked_at":"2025-08-10T02:00:08.965Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["functional-js","functional-programming","monad-library","monad-ts","monads","store","typescript","typescript-library"],"created_at":"2025-08-18T19:17:04.763Z","updated_at":"2025-08-18T19:17:10.114Z","avatar_url":"https://github.com/sash-ua.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/sash-ua/monad-ts.svg?branch=master)](https://travis-ci.org/sash-ua/monad-ts)\n[![npm](https://img.shields.io/npm/dw/localeval.svg)](https://github.com/sash-ua/monad-ts)\n[![Gemnasium](https://img.shields.io/gemnasium/mathiasbynens/he.svg)](https://github.com/sash-ua/monad-ts)\n[![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](https://github.com/sash-ua/monad-ts)\n\n\n# Monad-ts\n\nMonad-ts is a small library implements some of key monads and way to chain them in a flow (pipe) in JavaScript and\nTypescript. Angular 2+ compatible\n\n[Example app 1](https://github.com/sash-ua/gen_drift_monad-ts_a4/).\n\n[Example app 2 with monad transformers](https://github.com/sash-ua/todos-next).\n\n## Content\n* [Installation](#installation)\n* [Tests](#tests)\n\n**Introduction**\n* [Intro](#intro)\n* [Setup](#setup)\n* [API](https://sash-ua.github.io/monad-ts/identifiers.html)\n\n**All monads**\n* [Either](#either)\n* [ErrorM](#errorm)\n* [Identity](#identity)\n* [Maybe](#maybe)\n* [List](#list)\n* [State](#state)\n\n**Additional tools (class and functions)**\n* [AsyncFlow](#asyncflow)\n* [Flow](#flow)\n* [cast](#cast)\n* [clone](#clone)\n* [debounceTime](#debouncetime)\n* [equality](#equality)\n* [hash](#hash)\n* [wait](#wait)\n\n**Examples**\n* [Monad examples](https://github.com/sash-ua/monad-ts/tree/master/test)\n* [Monad transformer examples](https://github.com/sash-ua/todos-next/blob/master/src/app/services/monad.service/monad.service.ts)\n* [App 1](https://github.com/sash-ua/gen_drift_monad-ts_a4)\n* [App 2 with Monad transformers](https://github.com/sash-ua/todos-next)\n\n## Installation\n\nIn library used ES5 (Array.map, Array.reduce, Array.some, Array.isArray, Object.getOwnPropertyNames), ES6 (Map, Array.from,\n Object.assign, Object.keys, Object.is) methods.\n It's strongly recommended to always use ES5-shim and ES6-shim or alternatives.\n```\nnpm install monad-ts\n```\nor\n```\n yarn add monad-ts\n```\n\n## Tests\n\nClone the repo, `npm install` or `yarn` and run tests.\n```\nnpm run test\n```\nor\n```\n yarn test\n```\n\n## Intro\n\nOne of the main ideas of functional programming is to use pure functions as much as possible. But pure functions\ndon't do any kind of side-effects. At the same time the majority of programs should operate with side-effects in\nprocess. Monads allow us to do all the side-effecting computations using pure functions effectively.\n\n**NB** This monads implementation aren't exact copy of Haskell monads. My goal was to reach results comparable with the\nusing of like monads from Haskell in JS.\n\n**NB** For catching Errors, produced within monads you should use monad ErrorM.\n\n## Setup\n\n**1.** **SystemJS** Configure `systemjs.config.js` to register the module.\n```\nSystemJS.config({\n\tmap:{\n\t\t...\n\t\t'monad-ts': 'node_modules/monad-ts/lib/monad_ts.umd.js'\n\t\t...\n\t}\n})\n```\n**2.** **WebPack** No special configuration.\n\nExample:\n```ts\nimport {Flow, List} from \"monad-ts\"\n\nconst list = new List();\nconst e: number = 50;\nlet r : number;\nlet t : number[];\nconsole.log(t); // undefined\nconsole.log(r); // undefined\nconst z = new Flow(5)\n    .bind((v: number): any =\u003e v+1)\n    .let((v: number): any =\u003e new Flow(v).bind((v: number) =\u003e r = v+e))\n    .bind((v: number): any =\u003e cast(list.bind((v: number) =\u003e [v-1, v, v+1], [-v, v ]), 1))\n    .let((v: number)=\u003e new Flow(v).bind((v: number[]) =\u003e t = v, cast(list.bind((v: number)=\u003e[v, -v], [v]), 2)))\n    .subscribe();\nconsole.log(r); // 56\nconsole.log(t); // [ -7, 7, -6, 6, -5, 5, 5, -5, 6, -6, 7, -7 ]\nconsole.log(z); // [ -7, -6, -5, 5, 6, 7 ]\n```\n\n[UP](#monad-ts)\n\n## Monads\n\n#### Either\n\nIt represents computation with two possibilities, `right` and `left`. Attached by bind method dispatcher function decided\nwhich of them apply to underlying value.\n\nExample:\n```ts\nconst uVal = 10;                                     // underlying value\nconst right = (x: number) =\u003e x+1;                    // if cond(v) return true, than executed\nconst left = (y: string) =\u003e y + ' - isn\\'t string';  // if cond(v) return false, than executed\nconst cond = (v:any) =\u003e typeof v === 'string';       // dispatcher function - cond(v)\nconst e = new Either(right, left).bind(cond , uVal); // '10 - isn't string'\n```\n\n#### ErrorM\n\nIt similar to the Identity but it can also represent the error. Error monad returns value transformed by given function.\nIf Error monad gets Error in given values it produce Error. If after application of given transformation function monad\nget Error monad produce Error.\n\nExamples:\n```ts\nconst e = new ErrorM();\ne.bind((v: number) =\u003e e.bind((v1: number)=\u003ev+v1, 1), 1/0); // Error\n```\n\n#### Identity\n\nIt returns underlying value transformed by given function. We can add underlying value in constructor or in bind method.\n\nExamples:\n```ts\nconst i = new Identity(3);    // Identity({v: 3})\ni.bind((v:number) =\u003e v);      // 3\n```\n```ts\nconst i = new Identity();\ni.bind((v:number) =\u003e v, 3); // 3\n```\n\n#### Maybe\n\nIt similar to the Identity but it can also represent the absence of any value. Monad Maybe returns value transformed\nby given function. If Maybe monad gets null or undefined in given values it produce null. If after application of given\ntransformation function monad get null or undefined monad produce null.\n\nExamples:\n```ts\nconst maybe = new Maybe();\ntype G = { url: string; getUrl: () =\u003e any; };\nconst z: G = {\n    url: 'http://...',\n    getUrl: function (){\n        return this.url;\n    }\n};\nmaybe.bind(r =\u003e r.getUrl(), z); // http://...\n```\n\n#### List\n\nThe List monad represents a computed list of values. It takes in an input value of type A, and produce a bunch of output\n values of type B, collected in one container (the array).\n\nIt get array and return array, to cast array dimension according to entered array we can use function [cast](#cast);\n\nExamples:\n```ts\nconst list = new List();\nconst x = [10, 2];                                                                         // Entered array\nz = cast(list.bind((v: number) =\u003e list.bind((v: number) =\u003e [-v, v], [v-1, v, v+1]), x), 2); // [ -9, 9, -10, 10, -11, 11, -1, 1, -2, 2,\n-3, 3 ]\n```\n\n#### State\n\nThe State monad interact with local and global state variables to transform them. After initializing an instance of State monad we can not\nadd new keys to the state object.\nIt take object.\n\nThe instance of the State monad can be initialized in two ways.\n\n1. While the instance create - in constructor (Ex.1).\n\n2. After instance created - use `bind()` method (Ex.2). The function `x =\u003e x` in `st.bind(x =\u003e x, initState);` is for backward\ncompatibility with previous versions, it's unused in the method. Delayed initialization can be useful in some cases.\n\nExample 1:\n```ts\ntype R = { data: number; children: any[]; arr: number[]; };\n    const initState: R = {\n        data: 1,\n        children: [{\n            data: 2,\n            parent: 'null'\n        }],\n        arr:[1,2,3]\n    };\n    const st = new State(initState);\n    console.log(st.get()); // return initState object\n    st.put((v: R) =\u003e {\n                v.data = 10;\n                v.arr = list.bind((x:number) =\u003e x+f, v.arr);\n                return v;\n            });\n    console.log(st.get()); // { data: 10, children: [ Object({ data: 2, parent: 'null' }) ], arr: [ 2.25, 3.25, 4.25 ] }\n```\nExample 2:\n```ts\ntype R = { data: number; children: any[]; arr: number[]; };\n    const initState: R = {\n        data: 1,\n        children: [{\n            data: 2,\n            parent: null\n        }],\n        arr:[1,2,3]\n    };\n    const st = new State();\n    console.log(st.get()); // State -\u003e undefined\n    st.bind(x =\u003e x, initState);\n    st.put((v: R) =\u003e {\n                v.data = 10;\n                v.arr = list.bind((x:number) =\u003e x+f, v.arr);\n                return v;\n            });\n    console.log(st.get()); // State -\u003e { data: 10, children: [ Object({ data: 2, parent: null }) ], arr: [ 2.25, 3.25, 4.25 ] }\n```\n[UP](#monad-ts)\n\n## Additional utilities (class and functions)\n\n#### AsyncFlow\nFor composing monads in an async flow (pipe), based on Promise. Class instance creation `new AsyncFlow(initV,\nencapsulate?)`. Initial value (initV) encapsulated in the class instance by default. If set encapsulate = false, then\ninitial value wouldn't be encapsulated and we will be able to change inner state of the class instance by changing\n`initV`.\n\n**NB** Initial value should be statically analyzable.\n```ts\nnew AsyncFlow(5)\n  .bind((v) =\u003e v)\n  .then((v) =\u003e v)\n  .then((v) =\u003e cast(list.bind((v:number) =\u003e [v-1, v, v+1], [v]), 1))\n  .then(v=\u003e wait(v,100))\n  .then((v)=\u003e {\n      console.log(v);                 // v = [4,5,6], emitted after 100 ms\n  });\n```\n\n#### Flow\nFor composing monads in a flow (pipe). Class instance creation is identical to AsyncFlow.\n```ts\nconst e: number = 50;\nlet r : number;\nlet t : number[];\nconst z = new Flow(5)\n  .bind((v: number): any =\u003e v+1)\n  .let((v: number): any =\u003e new Flow(v).bind((v: number) =\u003e r = v+e))\n  .bind((v: number): any =\u003e cast(list.bind((v: number) =\u003e [v-1, v, v+1], [-v, v ]), 1))\n  .let((v: number)=\u003e new Flow(v).bind((v: number[]) =\u003e t = v, cast(list.bind((v: number)=\u003e[v, -v], [v]), 2)))\n  .subscribe();\nconsole.log(r); // 56\nconsole.log(t); // [ -7, 7, -6, 6, -5, 5, 5, -5, 6, -6, 7, -7 ]\nconsole.log(z); // [ -7, -6, -5, 5, 6, 7 ]\n```\n\n#### cast\nFunction to decreasing the dimension of an array by factor `n`. It takes array and factor.\n```ts\nconsole.log(cast([10, [11], [12]], 0));           // [10, [11], [12]]\nconsole.log(cast([10, [[11, [2]], 3], [12]], 2)); // [ 10, 11, [ 2 ], 3, 12 ]\n```\n\n#### clone\nFunction to clone objects (including Map). It takes objects, arrays and primitives.\n```ts\nconst x = {x:1};\nconst z = clone(x);\nz.x = 10;\nconsole.log(z); // {x:10}\nconsole.log(x); // {x:1}\n```\n\n#### debounceTime\nExecute a function given a delay time. `debounceTime(func, d, i?)`, `func` - invoked function, `d` - a delay time,\n`i` - delay before `func` execution, by default is absent.\n\n#### equality\nIt checks equality of given arguments, arguments must be statically analyzable, therefore there are some constraints,\nlook at **[examples]( https://sash-ua.github.io/monad-ts/function/index.html#static-function-equality )** to find\nthem.\n```ts\n// true\nequality(\n  {x1: 0, x: [1, {c: [22, {j:21, g: 'ert'}, 23]}, NaN, Infinity, null, undefined], t: [null, 0]},\n  {x1: 0, x: [1, {c: [22, {j:21, g: 'ert'}, 23]}, NaN, Infinity, null, undefined], t: [null, 0]}\n)\n```\n#### hash\nIt calculates a hash (32 bit).\n```ts\nlet g = hash('test \"#^test \"#^test \"#^testRrr G!@#$%^\u0026*()__+\u003c\u003e?ZXCV\":A'); // g = 2692353561\n```\n\n#### wait\nFunction to convert timeout in a Promise, resolved when specified amount of time passes. It take value (v) end emit\nPromise after t timeout with value (v). `wait(v, t)`\nIt produce a promise rejection handler on an Error occur.\n```ts\nconst s = wait(1, 300).then((v: number)=\u003e{\n            console.log(v);                 // v = 1, emitted after 300 ms\n        })\n```\n\n[UP](#monad-ts)\n\n## License\n\nMonad_ts is copyright (c) 2017 - present Alex Tranchenko tranchenkoa@gmail.com .\n\nMonad_ts is free software, licensed under the Apache License, Version 2.0. See the file LICENSE.md in this distribution\nfor more details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsash-ua%2Fmonad-ts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsash-ua%2Fmonad-ts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsash-ua%2Fmonad-ts/lists"}