├── .gitignore
├── .idea
├── .gitignore
├── fp-ts-talk-code.iml
├── modules.xml
└── vcs.xml
├── README.md
├── package-lock.json
├── package.json
├── src
├── Option
│ ├── absurd.ts
│ ├── compose-with-option.ts
│ ├── compose-with-undefined.ts
│ ├── option-chain.ts
│ ├── option-methods.ts
│ ├── option.ts
│ └── unions.ts
├── compose-no-pipe.ts
├── compose-pipe-debug.ts
├── compose-pipe.ts
├── create-user-function.ts
├── curry-functions.ts
├── data.ts
├── debug.ts
├── functions.ts
├── readonly.ts
├── string-utils.ts
└── types.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/fp-ts-talk-code.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # fp-ts-talk-code
2 | Примеры кода для доклада по fp-ts
3 |
4 | # Доклад
5 | [Функциональное программирование с использованием библиотеки fp-ts](https://youtu.be/LoeV7yeItkk "Функциональное программирование с использованием библиотеки fp-ts")
6 |
7 | # Документация
8 | https://gcanti.github.io/fp-ts/
9 |
10 | # Список литературы
11 | ## Книги
12 | - [Professor Frisby’s Mostly Adequate Guide to Functional Programming](https://github.com/MostlyAdequate/mostly-adequate-guide-ru/blob/master/SUMMARY-ru.md "Professor Frisby’s Mostly Adequate Guide to Functional Programming")
13 | ## Спецификация
14 | - [Fantasy Land Specification](https://github.com/fantasyland/fantasy-land "Fantasy Land Specification")
15 | - [Fantas, Eel, and Specification](http://www.tomharding.me/fantasy-land/ "Fantas, Eel, and Specification")
16 | ## Туториалы
17 | ### Функциональное программирование на TypeScript
18 | - [Функциональное программирование на TypeScript: полиморфизм родов высших порядков](https://habr.com/ru/post/526024/ "Функциональное программирование на TypeScript: полиморфизм родов высших порядков")
19 | - [Функциональное программирование на TypeScript: паттерн «класс типов»](https://habr.com/ru/post/534998/ "Функциональное программирование на TypeScript: паттерн «класс типов»")
20 | - [Функциональное программирование на TypeScript: Option и Either](https://habr.com/ru/post/544636/ "Функциональное программирование на TypeScript: Option и Either")
21 | - [Функциональное программирование на TypeScript: задачи (tasks) как альтернатива промисам](https://habr.com/ru/post/548622/ "Функциональное программирование на TypeScript: задачи (tasks) как альтернатива промисам")
22 | ### Getting started with fp-ts
23 | - [Introduction to Functional Programming](https://github.com/enricopolanski/functional-programming "Introduction to Functional Programming")
24 | - [Getting started with fp-ts: Eq](https://dev.to/gcanti/getting-started-with-fp-ts-setoid-39f3)
25 | - [Getting started with fp-ts: Ord](https://dev.to/gcanti/getting-started-with-fp-ts-ord-5f1e "Getting started with fp-ts: Ord")
26 | - [Getting started with fp-ts: Semigroup](https://dev.to/gcanti/getting-started-with-fp-ts-semigroup-2mf7 "Getting started with fp-ts: Semigroup")
27 | - [Getting started with fp-ts: Monoid](https://dev.to/gcanti/getting-started-with-fp-ts-monoid-ja0 "Getting started with fp-ts: Monoid")
28 | - [Getting started with fp-ts: Category](https://dev.to/gcanti/getting-started-with-fp-ts-category-4c9a "Getting started with fp-ts: Category")
29 | - [Getting started with fp-ts: Functor](https://dev.to/gcanti/getting-started-with-fp-ts-functor-36ek "Getting started with fp-ts: Functor")
30 | - [Getting started with fp-ts: Applicative](https://dev.to/gcanti/getting-started-with-fp-ts-applicative-1kb3 "Getting started with fp-ts: Applicative")
31 | - [Getting started with fp-ts: Monad](https://dev.to/gcanti/getting-started-with-fp-ts-monad-6k "Getting started with fp-ts: Monad")
32 | ### Practical Guide to Fp-ts
33 | - [Practical Guide to Fp-ts P1: Pipe and Flow](https://rlee.dev/practical-guide-to-fp-ts-part-1 "Practical Guide to Fp-ts P1: Pipe and Flow")
34 | - [Practical Guide to Fp-ts P2: Option, Map, Flatten, Chain](https://rlee.dev/practical-guide-to-fp-ts-part-2 "Practical Guide to Fp-ts P2: Option, Map, Flatten, Chain")
35 | - [Practical Guide to Fp-ts P3: Task, Either, TaskEither](https://rlee.dev/practical-guide-to-fp-ts-part-3 "Practical Guide to Fp-ts P3: Task, Either, TaskEither")
36 | - [Practical Guide to Fp-ts P4: Arrays, Semigroups, Monoids](https://rlee.dev/practical-guide-to-fp-ts-part-4 "Practical Guide to Fp-ts P4: Arrays, Semigroups, Monoids")
37 | - [Practical Guide to Fp-ts P5: Apply, Sequences, and Traversals](https://rlee.dev/practical-guide-to-fp-ts-part-5 "Practical Guide to Fp-ts P5: Apply, Sequences, and Traversals")
38 | - [Practical Guide to Fp-ts P6: The Do Notation](https://rlee.dev/practical-guide-to-fp-ts-p6-the-do-notation "Practical Guide to Fp-ts P6: The Do Notation")
39 | ## TypeScript
40 | - [TypeScript: Раскладываем tsconfig по полочкам. Часть 1](https://habr.com/ru/post/542234/ "TypeScript: Раскладываем tsconfig по полочкам. Часть 1")
41 | - [TypeScript: Раскладываем tsconfig по полочкам. Часть 2 — Всё про строгость](https://habr.com/ru/post/557738/ "TypeScript: Раскладываем tsconfig по полочкам. Часть 2 — Всё про строгость")
42 | - [Discriminated Unions](https://basarat.gitbook.io/typescript/type-system/discriminated-unions "Discriminated Unions")
43 | ## ESLint
44 | - [eslint-plugin-functional](https://github.com/jonaskello/eslint-plugin-functional "eslint-plugin-functional")
45 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fp-ts-talk-code",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@cspotcode/source-map-consumer": {
8 | "version": "0.8.0",
9 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
10 | "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
11 | "dev": true
12 | },
13 | "@cspotcode/source-map-support": {
14 | "version": "0.7.0",
15 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
16 | "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
17 | "dev": true,
18 | "requires": {
19 | "@cspotcode/source-map-consumer": "0.8.0"
20 | }
21 | },
22 | "@tsconfig/node10": {
23 | "version": "1.0.8",
24 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
25 | "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==",
26 | "dev": true
27 | },
28 | "@tsconfig/node12": {
29 | "version": "1.0.9",
30 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
31 | "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
32 | "dev": true
33 | },
34 | "@tsconfig/node14": {
35 | "version": "1.0.1",
36 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
37 | "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==",
38 | "dev": true
39 | },
40 | "@tsconfig/node16": {
41 | "version": "1.0.2",
42 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
43 | "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
44 | "dev": true
45 | },
46 | "@types/uuid": {
47 | "version": "8.3.3",
48 | "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.3.tgz",
49 | "integrity": "sha512-0LbEEx1zxrYB3pgpd1M5lEhLcXjKJnYghvhTRgaBeUivLHMDM1TzF3IJ6hXU2+8uA4Xz+5BA63mtZo5DjVT8iA==",
50 | "dev": true
51 | },
52 | "acorn": {
53 | "version": "8.6.0",
54 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz",
55 | "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==",
56 | "dev": true
57 | },
58 | "acorn-walk": {
59 | "version": "8.2.0",
60 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
61 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
62 | "dev": true
63 | },
64 | "arg": {
65 | "version": "4.1.3",
66 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
67 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
68 | "dev": true
69 | },
70 | "create-require": {
71 | "version": "1.1.1",
72 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
73 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
74 | "dev": true
75 | },
76 | "diff": {
77 | "version": "4.0.2",
78 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
79 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
80 | "dev": true
81 | },
82 | "fp-ts": {
83 | "version": "2.11.5",
84 | "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.11.5.tgz",
85 | "integrity": "sha512-OqlwJq1BdpB83BZXTqI+dNcA6uYk6qk4u9Cgnt64Y+XS7dwdbp/mobx8S2KXf2AXH+scNmA/UVK3SEFHR3vHZA=="
86 | },
87 | "make-error": {
88 | "version": "1.3.6",
89 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
90 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
91 | "dev": true
92 | },
93 | "prettier": {
94 | "version": "2.5.0",
95 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz",
96 | "integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==",
97 | "dev": true
98 | },
99 | "ts-node": {
100 | "version": "10.4.0",
101 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz",
102 | "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==",
103 | "dev": true,
104 | "requires": {
105 | "@cspotcode/source-map-support": "0.7.0",
106 | "@tsconfig/node10": "^1.0.7",
107 | "@tsconfig/node12": "^1.0.7",
108 | "@tsconfig/node14": "^1.0.0",
109 | "@tsconfig/node16": "^1.0.2",
110 | "acorn": "^8.4.1",
111 | "acorn-walk": "^8.1.1",
112 | "arg": "^4.1.0",
113 | "create-require": "^1.1.0",
114 | "diff": "^4.0.1",
115 | "make-error": "^1.1.1",
116 | "yn": "3.1.1"
117 | }
118 | },
119 | "typescript": {
120 | "version": "4.5.2",
121 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz",
122 | "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw=="
123 | },
124 | "uuid": {
125 | "version": "8.3.2",
126 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
127 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
128 | },
129 | "yn": {
130 | "version": "3.1.1",
131 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
132 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
133 | "dev": true
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fp-ts-talk-code",
3 | "version": "1.0.0",
4 | "description": "Примеры кода для доклада по fp-ts",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/dkhovrich/fp-ts-talk-code.git"
12 | },
13 | "keywords": [],
14 | "author": "",
15 | "license": "ISC",
16 | "bugs": {
17 | "url": "https://github.com/dkhovrich/fp-ts-talk-code/issues"
18 | },
19 | "homepage": "https://github.com/dkhovrich/fp-ts-talk-code#readme",
20 | "dependencies": {
21 | "fp-ts": "^2.11.5",
22 | "typescript": "^4.5.2",
23 | "uuid": "^8.3.2"
24 | },
25 | "devDependencies": {
26 | "@types/uuid": "^8.3.3",
27 | "prettier": "^2.5.0",
28 | "ts-node": "^10.4.0"
29 | },
30 | "prettier": {
31 | "trailingComma": "none",
32 | "tabWidth": 4,
33 | "semi": true,
34 | "singleQuote": false
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Option/absurd.ts:
--------------------------------------------------------------------------------
1 | function absurd(_: never): A {
2 | throw new Error('Called `absurd` function which should be uncallable')
3 | }
--------------------------------------------------------------------------------
/src/Option/compose-with-option.ts:
--------------------------------------------------------------------------------
1 | import {createUsers} from "../data";
2 | import {constant, pipe} from "fp-ts/function";
3 | import * as O from "fp-ts/Option";
4 | import * as A from "fp-ts/ReadonlyArray";
5 | import {byEmail, createFullName} from "../types";
6 | import {stringHash} from "../string-utils";
7 |
8 | const users = createUsers();
9 |
10 | const optionalUser = pipe(
11 | users,
12 | A.findFirst(byEmail("spider-man@gmail.com"))
13 | );
14 |
15 | console.log(optionalUser); // Option -> { _tag: 'Some', value: { id: 1, email: "spiderman@gmail.com" } }
16 |
17 | const optionalFullName = pipe(optionalUser, O.map(createFullName));
18 |
19 | console.log(optionalFullName); // Option -> { _tag: 'Some', value: 'Peter Parker' }
20 |
21 | const hero = pipe(
22 | users,
23 | A.findFirst(byEmail("spider-man@gmail.com")),
24 | O.map(createFullName)
25 | );
26 |
27 | console.log(hero); // Option -> { _tag: 'Some', value: 'Peter Parker' }
28 |
29 | const girl = pipe(
30 | users,
31 | A.findFirst(byEmail("marry-watson@gmail.com")),
32 | O.map(createFullName)
33 | );
34 |
35 | console.log(girl); // Option -> { _tag: 'None' }
36 |
37 | const result = pipe(
38 | users,
39 | A.findFirst(byEmail("spider-man@gmail.com")),
40 | O.map(createFullName),
41 | O.toUndefined
42 | );
43 |
44 | console.log(result); // string -> Peter Parker
45 |
46 | const result1 = pipe(
47 | users,
48 | A.findFirst(byEmail("iron-man@gmail.com")),
49 | O.map(createFullName),
50 | O.getOrElse(constant("Proof That Tony Stark Has A Heart"))
51 | )
52 |
53 | console.log(result1); // Proof That Tony Stark Has A Heart
54 |
55 | const fullNameHash = pipe(
56 | users,
57 | A.findFirst(byEmail("spiderman@gmail.com")),
58 | O.map(createFullName),
59 | O.map(stringHash)
60 | );
61 |
62 | console.log(fullNameHash); // Option -> { _tag: 'Some', value: -1021137173 }
--------------------------------------------------------------------------------
/src/Option/compose-with-undefined.ts:
--------------------------------------------------------------------------------
1 | import {createUsers} from "../data";
2 | import {pipe} from "fp-ts/function";
3 | import {byEmail, User} from "../types";
4 |
5 | const users = createUsers();
6 |
7 | declare function createFullName(user: User): string;
8 |
9 | // TS2345: Argument of type 'User | undefined' is not assignable to parameter of type 'User'
10 | // Type 'undefined' is not assignable to type 'User'.
11 | const result = pipe(
12 | users.find(byEmail("spider-man@gmail.com")),
13 | createFullName
14 | );
--------------------------------------------------------------------------------
/src/Option/option-chain.ts:
--------------------------------------------------------------------------------
1 | import { Comment } from "../types";
2 | import {createComments, createUsers} from "../data";
3 | import {constant, pipe} from "fp-ts/function";
4 | import * as O from "fp-ts/Option";
5 | import * as A from "fp-ts/ReadonlyArray";
6 | import * as R from "fp-ts/Record";
7 | import {byEmail} from "../types";
8 |
9 | const users = createUsers();
10 |
11 | const comments = createComments();
12 |
13 | // Option