├── API
├── db.json
└── start.bat
├── CH 00 ReactApp Linting 2
├── .eslintrc.json
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
│ └── index.html
└── src
│ ├── App.js
│ └── index.js
├── CH 00 ReactApp Linting
├── .eslintrc.json
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
│ └── index.html
└── src
│ ├── App.js
│ └── index.js
├── CH 00 Setup
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── hello.js
├── package-lock.json
├── package.json
└── run.bat
├── CH 02 Immutable Data
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── mutation.js
├── package-lock.json
├── package.json
└── run.bat
├── CH 03 Functions
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── arrow.js
├── functions.js
├── package-lock.json
├── package.json
├── pure.js
└── run.bat
├── CH 04 Array
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── changing.js
├── filter-objects.js
├── filter.js
├── find.js
├── forEach.js
├── impure.js
├── map-objects.js
├── map.js
├── package-lock.json
├── package.json
├── push.js
├── reduce-objects.js
├── reduce.js
├── run.bat
└── sort.js
├── CH 05 First-Class Functions
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── array-of-functions.js
├── counter.js
├── higher-order-sort.js
├── higher-order.js
├── package-lock.json
├── package.json
├── run.bat
└── run.js
├── CH 06 Statements
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── break-every.js
├── break-find.js
├── for.js
├── if-return.js
├── if-side-effects.js
├── if.js
├── package-lock.json
├── package.json
├── run.bat
├── switch-cond.js
├── switch-map.js
├── switch-return.js
├── switch.js
├── ternary.js
├── var.js
└── while.js
├── CH 07 Recursion
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── factorial-conditional.js
├── factorial-recursive.js
├── factorial-tc.js
├── factorial.js
├── package-lock.json
├── package.json
├── run.bat
├── stack-overflow-loop.js
├── stack-overflow.js
├── sum-loop.js
├── sum-recursive.js
├── trampoline.js
└── tree.js
├── CH 08 Pipelines
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── chaining-2.js
├── chaining-3.js
├── chaining.js
├── currying-1.js
├── currying-2.js
├── currying-3.js
├── currying-4.js
├── package-lock.json
├── package.json
├── pipe-weather.js
├── pipe.js
├── reduce.js
└── run.bat
├── CH 09 Functors
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── F.js
├── array.js
├── array_weather.js
├── mapping.js
├── package-lock.json
├── package.json
├── run.bat
├── test_F.js
└── test_F_weather.js
├── CH 10 Monads
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── Applicative.js
├── M-bind.js
├── M.js
├── Maybe.js
├── flat.js
├── flatMap.js
├── map.js
├── package-lock.json
├── package.json
├── run.bat
├── test_Array_laws.js
├── test_M.js
├── test_M_bind.js
└── test_M_laws.js
├── CH 11 Immutable Collections
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── List-Operations.js
├── List.js
├── Map-Operations.js
├── Map.js
├── package-lock.json
├── package.json
└── run.bat
├── CH 12 Lazy
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── Range.js
├── Seq.js
├── chain.js
├── filter.js
├── find.js
├── map.js
├── package-lock.json
├── package.json
├── prime-2.js
├── prime-3.js
├── prime.js
├── run.bat
└── transducer.js
├── CH 13 Generators
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── fibonacci.js
├── forEach.js
├── package-lock.json
├── package.json
├── pipe.js
├── range-finite.js
├── range.js
├── run.bat
├── take.js
├── test_fibonacci.js
├── test_forEach.js
├── test_range.js
├── test_range_finite.js
├── test_range_take.js
├── test_toArray.js
└── toArray.js
├── CH 14 Promises AJAX
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── all.js
├── allSettled.js
├── fetch.js
├── index.html
├── insequence.js
├── package-lock.json
├── package.json
├── race.js
└── run.bat
├── CH 14 Promises
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── catch.js
├── chain.js
├── delay.js
├── flat-mapping-2.js
├── flat-mapping-3.js
├── flat-mapping.js
├── laws-functor-1.js
├── laws-functor-2.js
├── laws-monad-3.js
├── mappable.js
├── package-lock.json
├── package.json
├── run.bat
└── timeout.js
├── CH 15 Observables AJAX
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── ajax.js
├── concatAll.js
├── forkJoin.js
├── hoo.js
├── index.html
├── insequence.js
├── package-lock.json
├── package.json
├── race.js
└── run.bat
├── CH 15 Observables
├── .babelrc
├── .eslintrc.json
├── .gitignore
├── combine.js
├── create.js
├── filter.js
├── from.js
├── interval.js
├── laws1.js
├── laws2.js
├── map.js
├── mergeAll.js
├── mergeMap.js
├── observers.js
├── of.js
├── package-lock.json
├── package.json
├── pipe.js
├── run.bat
├── subscription.js
└── take.js
├── CH 16 Elm Architecture
├── .gitignore
├── elm.json
├── run.bat
└── src
│ ├── Counter.elm
│ ├── RandomGenerator-update.js
│ └── RandomGenerator.elm
├── CH 16 Redux Commands
├── .eslintrc.json
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
│ └── index.html
└── src
│ ├── Counter.js
│ ├── index.js
│ └── store.js
├── CH 16 Redux
├── .eslintrc.json
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
│ └── index.html
└── src
│ ├── Counter.js
│ ├── index.js
│ └── store.js
├── CH 17 Redux Axios
├── .eslintrc.json
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
│ └── index.html
└── src
│ ├── List.jsx
│ ├── index.js
│ └── store.js
└── readme.md
/API/db.json:
--------------------------------------------------------------------------------
1 | {
2 | "todos": [
3 | {"id":1, "title": "To Do 1"}
4 | ],
5 | "dictionaries": [
6 | { "name": "Dictionary 1"}
7 | ]
8 | }
--------------------------------------------------------------------------------
/API/start.bat:
--------------------------------------------------------------------------------
1 | json-server --watch db.json
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting 2/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["react-app"],
3 | "plugins": [
4 | "immutable"
5 | ],
6 | "rules": {
7 | "immutable/no-this": "error",
8 | "immutable/no-mutation": "error"
9 | }
10 | }
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting 2/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting 2/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `npm start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `npm test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `npm run build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `npm run eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `npm run build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting 2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "my-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.5.0",
8 | "@testing-library/user-event": "^7.2.1",
9 | "react": "^16.13.1",
10 | "react-dom": "^16.13.1",
11 | "react-scripts": "3.4.1"
12 | },
13 | "scripts": {
14 | "start": "npx eslint src && react-scripts start",
15 | "build": "react-scripts build",
16 | "test": "react-scripts test",
17 | "eject": "react-scripts eject"
18 | },
19 | "eslintConfig": {
20 | "extends": "react-app"
21 | },
22 | "browserslist": {
23 | "production": [
24 | ">0.2%",
25 | "not dead",
26 | "not op_mini all"
27 | ],
28 | "development": [
29 | "last 1 chrome version",
30 | "last 1 firefox version",
31 | "last 1 safari version"
32 | ]
33 | },
34 | "devDependencies": {
35 | "eslint": "^7.1.0",
36 | "eslint-plugin-immutable": "^1.0.0"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting 2/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 | You need to enable JavaScript to run this app.
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting 2/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function App() {
4 | return (
5 |
6 | Learn React
7 |
8 | );
9 | }
10 |
11 | export default App;
12 |
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting 2/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | const a = {
6 | x:1
7 | }
8 |
9 | ReactDOM.render(
10 |
11 |
12 | ,
13 | document.getElementById('root')
14 | );
15 |
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["react-app"],
3 | "plugins": [
4 | "functional"
5 | ],
6 | "rules": {
7 | "functional/no-this-expression": "error"
8 | }
9 | }
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `npm start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `npm test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `npm run build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `npm run eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `npm run build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "my-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.5.0",
8 | "@testing-library/user-event": "^7.2.1",
9 | "react": "^16.13.1",
10 | "react-dom": "^16.13.1",
11 | "react-scripts": "3.4.1"
12 | },
13 | "scripts": {
14 | "start": "npx eslint src && react-scripts start",
15 | "build": "react-scripts build",
16 | "test": "react-scripts test",
17 | "eject": "react-scripts eject"
18 | },
19 | "eslintConfig": {
20 | "extends": "react-app"
21 | },
22 | "browserslist": {
23 | "production": [
24 | ">0.2%",
25 | "not dead",
26 | "not op_mini all"
27 | ],
28 | "development": [
29 | "last 1 chrome version",
30 | "last 1 firefox version",
31 | "last 1 safari version"
32 | ]
33 | },
34 | "devDependencies": {
35 | "eslint": "^7.1.0",
36 | "eslint-plugin-functional": "^3.0.1"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 | You need to enable JavaScript to run this app.
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function App() {
4 | return (
5 |
6 | Learn React
7 |
8 | );
9 | }
10 |
11 | export default App;
12 |
--------------------------------------------------------------------------------
/CH 00 ReactApp Linting/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render(
6 |
7 |
8 | ,
9 | document.getElementById('root')
10 | );
11 |
--------------------------------------------------------------------------------
/CH 00 Setup/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 00 Setup/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "parserOptions": {
7 | "ecmaVersion": 11,
8 | "sourceType": "module"
9 | },
10 | "plugins": [
11 | "functional"
12 | ],
13 | "rules": {
14 | "functional/no-this-expression": "error"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/CH 00 Setup/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 00 Setup/hello.js:
--------------------------------------------------------------------------------
1 | console.log("hello");
--------------------------------------------------------------------------------
/CH 00 Setup/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2"
15 | },
16 | "devDependencies": {
17 | "eslint": "^7.6.0",
18 | "eslint-plugin-functional": "^3.0.1"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/CH 00 Setup/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node hello.js
--------------------------------------------------------------------------------
/CH 02 Immutable Data/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 02 Immutable Data/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "globals": {
7 | },
8 | "parserOptions": {
9 | "ecmaVersion": 11,
10 | "sourceType": "module"
11 | },
12 | "plugins": [
13 | "functional"
14 | ],
15 | "rules": {
16 | "functional/no-this-expression": "error",
17 | "functional/immutable-data": "error"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/CH 02 Immutable Data/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 02 Immutable Data/mutation.js:
--------------------------------------------------------------------------------
1 | const counter = {
2 | value: 1
3 | };
4 |
5 | counter.value = 2;
6 | delete counter.value;
7 | Object.assign(counter, { value: 2 });
8 |
9 | //Modifying properties of existing object not allowed.
--------------------------------------------------------------------------------
/CH 02 Immutable Data/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2"
15 | },
16 | "devDependencies": {
17 | "eslint": "^7.1.0",
18 | "eslint-plugin-functional": "^3.0.1"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/CH 02 Immutable Data/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node object.js
--------------------------------------------------------------------------------
/CH 03 Functions/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 03 Functions/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "extends": "eslint:recommended",
7 | "globals": {
8 | },
9 | "parserOptions": {
10 | "ecmaVersion": 11,
11 | "sourceType": "module"
12 | },
13 | "rules": {
14 | "functional/no-this-expression": "error",
15 | "functional/immutable-data": "error"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/CH 03 Functions/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 03 Functions/arrow.js:
--------------------------------------------------------------------------------
1 | const sum = (x, y) => x + y;
2 |
3 | console.log(sum(1,2));
--------------------------------------------------------------------------------
/CH 03 Functions/functions.js:
--------------------------------------------------------------------------------
1 | console.log(sum(1,2));
2 |
3 | function sum(x, y){
4 | return x + y;
5 | }
--------------------------------------------------------------------------------
/CH 03 Functions/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2"
15 | },
16 | "devDependencies": {
17 | "eslint": "^7.1.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/CH 03 Functions/pure.js:
--------------------------------------------------------------------------------
1 | function sum(x, y){
2 | return x + y;
3 | }
4 |
5 | function sumAll(arr){
6 | return arr.reduce(sum, 0);
7 | }
8 |
9 | console.log(sumAll([1, 2, 3]));
10 | //6
--------------------------------------------------------------------------------
/CH 03 Functions/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node functions.js
--------------------------------------------------------------------------------
/CH 04 Array/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 04 Array/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "globals": {
7 | },
8 | "parserOptions": {
9 | "ecmaVersion": 11,
10 | "sourceType": "module"
11 | },
12 | "plugins": [
13 | "functional"
14 | ],
15 | "rules": {
16 | "functional/no-this-expression": "error",
17 | "functional/immutable-data": "error",
18 | "no-var": "error",
19 | "functional/no-conditional-statement": ["error", {
20 | "allowReturningBranches": "ifExhaustive"
21 | }],
22 | "functional/no-loop-statement": "error",
23 | "functional/no-throw-statement": "error"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/CH 04 Array/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 04 Array/changing.js:
--------------------------------------------------------------------------------
1 | const games = [
2 | {id: 1, title: 'WarCraft'},
3 | {id: 2, title: 'X-COM: UFO Defense' }
4 | ]
5 |
6 | //adding
7 | const newValue = {id: 3, title: 'The Settlers'};
8 | const newGames = games.concat([newValue]);
9 | console.log(newGames);
10 | //[ { id: 1, title: 'WarCraft' },
11 | // { id: 2, title: 'X-COM: UFO Defense' },
12 | // { id: 3, title: 'The Settlers' } ]
13 |
14 | //editing
15 | const id = 1;
16 | const newValue2 = {id, title: 'WarCraft 2'};
17 |
18 | const newGames2 = games.map(game =>
19 | (game.id === id)
20 | ? newValue2
21 | : game
22 | );
23 | console.log(newGames2);
24 | //[ { id: 1, title: 'WarCraft 2' },
25 | // { id: 2, title: 'X-COM: UFO Defense' } ]
26 |
27 | //deleting
28 | const newGames3 = games.filter(game => game.id !== id);
29 | console.log(newGames3);
30 | //[ { id: 2, title: 'X-COM: UFO Defense' } ]
--------------------------------------------------------------------------------
/CH 04 Array/filter-objects.js:
--------------------------------------------------------------------------------
1 | const games = [
2 | { title: 'Starcraft', genre: 'RTS' },
3 | { title: 'Command and Conquer', genre: 'RTS' },
4 | { title: 'Heroes of Might and Magic', genre: 'TBS' },
5 | { title: 'World of Warcraft', genre : 'MMORPG'}
6 | ]
7 |
8 | function isStrategy(game){
9 | const strategyGenres = ['RTS', 'RTT', 'TBS', 'TBT'];
10 | return strategyGenres.includes(game.genre);
11 | }
12 |
13 | const strategyGames = games
14 | .filter(isStrategy);
15 |
16 | console.log(strategyGames);
17 | //[ { title: 'Starcraft', genre: 'RTS' },
18 | // { title: 'Command and Conquer', genre: 'RTS' },
19 | // { title: 'Heroes of Might and Magic', genre: 'TBS' } ]
--------------------------------------------------------------------------------
/CH 04 Array/filter.js:
--------------------------------------------------------------------------------
1 | const numbers = [1, 2, 3, 4];
2 |
3 | function isEven(n) {
4 | return n % 2 == 0;
5 | }
6 |
7 | const evenNumbers = numbers.filter(isEven);
8 | console.log(evenNumbers);
--------------------------------------------------------------------------------
/CH 04 Array/find.js:
--------------------------------------------------------------------------------
1 | const games = [
2 | { title: 'Starcraft 2', genre: 'RTS' },
3 | { title: 'Desperados 3', genre : 'RTT'},
4 | { title: 'Candy Crush Saga ', genre : 'Tile-matching'}
5 | ];
6 |
7 | function isStrategy(game){
8 | const strategyGenres = ['RTS', 'RTT', 'TBS', 'TBT'];
9 | return strategyGenres.includes(game.genre);
10 | }
11 |
12 | const first = games.find(isStrategy);
13 | console.log(first);
14 | //{ title: 'Starcraft 2', genre: 'RTS' }
15 |
16 | const firstIndex = games.findIndex(isStrategy);
17 | console.log(firstIndex);
18 | //0
19 |
20 | const areAll = games.every(isStrategy);
21 | console.log(areAll);
22 | //false
23 |
24 | const hasOne = games.some(isStrategy);
25 | console.log(hasOne);
26 | //true
--------------------------------------------------------------------------------
/CH 04 Array/forEach.js:
--------------------------------------------------------------------------------
1 | const numbers = [1, 2, 3, 4]
2 |
3 | function log(value){
4 | console.log(value);
5 | }
6 |
7 | numbers
8 | .forEach(log);
9 |
--------------------------------------------------------------------------------
/CH 04 Array/impure.js:
--------------------------------------------------------------------------------
1 | const arr = [1, 2, 3];
2 |
3 | arr.push(4);
4 | arr.pop();
5 |
6 | arr.unshift(0);
7 | arr.shift();
8 |
9 | //Modifying an array is not allowed
10 |
--------------------------------------------------------------------------------
/CH 04 Array/map-objects.js:
--------------------------------------------------------------------------------
1 | const games = [
2 | { title: 'Starcraft', genre: 'RTS' },
3 | { title: 'Command and Conquer', genre: 'RTS' },
4 | { title: 'Heroes of Might and Magic', genre: 'TBS' },
5 | { title: 'World of Warcraft', genre : 'MMORPG'}
6 | ]
7 |
8 | function toGameHtml(game){
9 | return `${game.title}
`;
10 | }
11 |
12 | const htmlRows = games
13 | .map(toGameHtml);
14 |
15 | console.log(htmlRows);
16 | // [ 'Starcraft
',
17 | // 'Command and Conquer
',
18 | // 'Heroes of Might and Magic
',
19 | // 'World of Warcraft
' ]
20 |
21 | console.log(htmlRows.join(''));
22 | //"Starcraft
Command and Conquer
Heroes of Might and Magic
World of Warcraft
"
23 |
--------------------------------------------------------------------------------
/CH 04 Array/map.js:
--------------------------------------------------------------------------------
1 | const numbers = [1, 2, 3, 4];
2 |
3 | function triple(n) {
4 | return n * 3;
5 | }
6 |
7 | const newNumbers = numbers.map(triple);
8 | console.log(newNumbers);
--------------------------------------------------------------------------------
/CH 04 Array/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2"
15 | },
16 | "devDependencies": {
17 | "eslint": "^7.1.0",
18 | "eslint-plugin-functional": "^3.0.1"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/CH 04 Array/push.js:
--------------------------------------------------------------------------------
1 | const arr = [1, 2, 3];
2 | newArr.push(4);
3 |
4 | console.log(newArr);
--------------------------------------------------------------------------------
/CH 04 Array/reduce-objects.js:
--------------------------------------------------------------------------------
1 | const games = [
2 | { title: 'Starcraft', genre: 'RTS' },
3 | { title: 'Command and Conquer', genre: 'RTS' },
4 | { title: 'Heroes of Might and Magic', genre: 'TBS' },
5 | { title: 'World of Warcraft', genre : 'MMORPG'}
6 | ];
7 |
8 | function countByGenre(countMap, game){
9 | const count = countMap[game.genre] || 0;
10 | return {
11 | ...countMap,
12 | [game.genre]: count + 1
13 | }
14 | }
15 |
16 | const gamesByGenreCounts = games
17 | .reduce(countByGenre, {});
18 |
19 | console.log(gamesByGenreCounts);
20 | //{ RTS: 2, TBS: 1, MMORPG: 1 }
21 |
--------------------------------------------------------------------------------
/CH 04 Array/reduce.js:
--------------------------------------------------------------------------------
1 | const numbers = [1, 3, 5, 7];
2 |
3 | function add(total, n) {
4 | return total + n;
5 | }
6 |
7 | const total = numbers.reduce(add, 0);
8 | console.log(total);
--------------------------------------------------------------------------------
/CH 04 Array/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node ma-objects.js
--------------------------------------------------------------------------------
/CH 04 Array/sort.js:
--------------------------------------------------------------------------------
1 | const numbers = [4, 2, 3, 1];
2 |
3 | function asc(a, b) {
4 | if(a === b){
5 | return 0
6 | } else {
7 | if (a < b){
8 | return -1;
9 | } else {
10 | return 1;
11 | }
12 | }
13 | }
14 |
15 | const sortedNumbers = numbers.slice().sort(asc);
16 | console.log(sortedNumbers);
--------------------------------------------------------------------------------
/CH 05 First-Class Functions/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 05 First-Class Functions/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "extends": "eslint:recommended",
7 | "globals": {
8 | },
9 | "parserOptions": {
10 | "ecmaVersion": 11,
11 | "sourceType": "module"
12 | },
13 | "rules": {
14 | "functional/no-this-expression": "error",
15 | "functional/immutable-data": "error"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/CH 05 First-Class Functions/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 05 First-Class Functions/array-of-functions.js:
--------------------------------------------------------------------------------
1 | function toUpperCase(text){
2 | return text.toUpperCase();
3 | }
4 |
5 | function toLowerCase(text){
6 | return text.toLowerCase();
7 | }
8 |
9 | function trim(text){
10 | return text.trim();
11 | }
12 |
13 | const functions = [
14 | toUpperCase,
15 | toLowerCase,
16 | trim
17 | ];
18 |
19 | const text = ' StARt!';
20 | functions.forEach(f =>{
21 | const newText = f(text);
22 | console.log(newText);
23 | });
24 | //"START!"
25 | //"start!"
26 | //"StARt!"
--------------------------------------------------------------------------------
/CH 05 First-Class Functions/counter.js:
--------------------------------------------------------------------------------
1 | function createCount(){
2 | let counter = 0;
3 | return function (){
4 | counter = counter + 1;
5 | return counter;
6 | }
7 | }
8 |
9 | const count = createCount();
10 | console.log(count());
11 | console.log(count());
12 | console.log(count());
--------------------------------------------------------------------------------
/CH 05 First-Class Functions/higher-order-sort.js:
--------------------------------------------------------------------------------
1 | const courses = [
2 | {
3 | title: '2',
4 | author: '2'
5 | },
6 | {
7 | title: '3',
8 | author: '3'
9 | },
10 | {
11 | title: '1',
12 | author: '1'
13 | }
14 | ];
15 |
16 | function by(name){
17 | return function(a, b){
18 | return a[name].localeCompare(b[name]);
19 | }
20 | }
21 |
22 | courses
23 | .slice().sort(by('author'));
--------------------------------------------------------------------------------
/CH 05 First-Class Functions/higher-order.js:
--------------------------------------------------------------------------------
1 | const objects = [
2 | { id: 1 },
3 | { id: 2 }
4 | ];
5 |
6 | function hasId(id){
7 | return function(element){
8 | return element.id === id;
9 | }
10 | }
11 |
12 | console.log(objects.find(hasId(1)));
--------------------------------------------------------------------------------
/CH 05 First-Class Functions/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2"
15 | },
16 | "devDependencies": {
17 | "eslint": "^7.1.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/CH 05 First-Class Functions/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node functions.js
--------------------------------------------------------------------------------
/CH 05 First-Class Functions/run.js:
--------------------------------------------------------------------------------
1 | function run(){
2 | const value = 1;
3 |
4 | function logValue(){
5 | console.log(value);
6 | }
7 |
8 | logValue();
9 | }
10 |
11 | run();
--------------------------------------------------------------------------------
/CH 06 Statements/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 06 Statements/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "globals": {
7 | },
8 | "parserOptions": {
9 | "ecmaVersion": 11,
10 | "sourceType": "module"
11 | },
12 | "plugins": [
13 | "functional"
14 | ],
15 | "rules": {
16 | "functional/no-this-expression": "error",
17 | "functional/immutable-data": "error",
18 | "no-var": "error",
19 | "functional/no-conditional-statement": ["error", {
20 | "allowReturningBranches": "ifExhaustive"
21 | }],
22 | "functional/no-loop-statement": "error",
23 | "functional/no-throw-statement": "error"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/CH 06 Statements/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 06 Statements/break-every.js:
--------------------------------------------------------------------------------
1 | const words = [
2 | 'ability',
3 | 'calculate',
4 | 'calendar',
5 | 'double',
6 | 'door'
7 | ];
8 |
9 | const stopTo = 'double';
10 | for(let word of words){
11 | if(word === stopTo){
12 | break;
13 | }
14 |
15 | console.log(word);
16 | }
17 |
18 | words.every(w => {
19 | if(w.startsWith(stopTo)){
20 | return false;
21 | } else {
22 | console.log(w);
23 | return true;
24 | }
25 | });
--------------------------------------------------------------------------------
/CH 06 Statements/break-find.js:
--------------------------------------------------------------------------------
1 | const products = [
2 | {id:1, name: 'apple'},
3 | {id:2, name:'mango'}
4 | ];
5 |
6 | const id = 1;
7 | let product;
8 | for(let i=0; i p.id === id);
19 | console.log(product1)
--------------------------------------------------------------------------------
/CH 06 Statements/for.js:
--------------------------------------------------------------------------------
1 | const book = {
2 | title : "How JavaScript Works",
3 | author : "Douglas Crockford"
4 | };
5 |
6 | for (const propName in book) {
7 | console.log(book[propName])
8 | }
9 |
10 | Object.keys(book).forEach(propName => {
11 | console.log(book[propName])
12 | });
13 |
14 | const arr = [1, 2, 3];
15 | for (const element of arr) {
16 | console.log(element);
17 | }
18 |
19 | arr.forEach(element => {
20 | console.log(element);
21 | });
--------------------------------------------------------------------------------
/CH 06 Statements/if-return.js:
--------------------------------------------------------------------------------
1 | function isEven(n){
2 | if(n % 2 === 0){
3 | return true;
4 | } else {
5 | return false;
6 | }
7 | }
8 |
9 | console.log(isEven(3));
--------------------------------------------------------------------------------
/CH 06 Statements/if-side-effects.js:
--------------------------------------------------------------------------------
1 | const isValid = true;
2 |
3 | if(isValid) {
4 | doSomething()
5 | }
6 |
7 | // short circuit
8 | isValid && doSomething()
9 |
10 | function doSomething(){
11 | console.log("side-effect");
12 | }
--------------------------------------------------------------------------------
/CH 06 Statements/if.js:
--------------------------------------------------------------------------------
1 | const n = 3;
2 | let isEven;
3 |
4 | if(n % 2 === 0){
5 | isEven = true;
6 | } else {
7 | isEven = false;
8 | }
9 |
10 | console.log(isEven)
11 |
12 |
--------------------------------------------------------------------------------
/CH 06 Statements/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2",
15 | "ramda": "^0.27.0"
16 | },
17 | "devDependencies": {
18 | "eslint": "^7.1.0",
19 | "eslint-plugin-functional": "^3.0.1"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/CH 06 Statements/run.bat:
--------------------------------------------------------------------------------
1 | npx eslint .
2 | npx babel-node if.js
--------------------------------------------------------------------------------
/CH 06 Statements/switch-cond.js:
--------------------------------------------------------------------------------
1 | import {cond, equals, identity, T} from 'ramda'
2 |
3 | function increment(x){
4 | return x + 1;
5 | }
6 |
7 | function decrement(x){
8 | return x - 1;
9 | }
10 |
11 | const doAction = cond([
12 | [equals('increment'), () => increment],
13 | [equals('decrement'), () => decrement],
14 | [T, ()=> identity]
15 | ]);
16 |
17 | const number = 0;
18 | const newNumber = doAction('increment')(number);
19 | console.log(newNumber)
--------------------------------------------------------------------------------
/CH 06 Statements/switch-map.js:
--------------------------------------------------------------------------------
1 | function increment(x){
2 | return x + 1;
3 | }
4 |
5 | function decrement(x){
6 | return x - 1;
7 | }
8 |
9 | const actionMap = {
10 | increment,
11 | decrement
12 | }
13 |
14 | function doAction(x, actionName){
15 | const action = actionMap[actionName];
16 | return action
17 | ? action(x)
18 | : x;
19 | }
20 |
21 | const number = 0;
22 | const newNumber = doAction(number, 'increment');
23 | console.log(newNumber)
--------------------------------------------------------------------------------
/CH 06 Statements/switch-return.js:
--------------------------------------------------------------------------------
1 | function increment(x){
2 | return x + 1;
3 | }
4 |
5 | function decrement(x){
6 | return x - 1;
7 | }
8 |
9 | function doAction(x, actionName){
10 | switch(actionName){
11 | case 'increment':
12 | return increment(x);
13 | case 'decrement':
14 | return decrement(x);
15 | default:
16 | return x;
17 | }
18 | }
19 |
20 | const number = 0;
21 | const newNumber = doAction(number, 'increment');
22 | console.log(newNumber)
--------------------------------------------------------------------------------
/CH 06 Statements/switch.js:
--------------------------------------------------------------------------------
1 | function increment(x){
2 | return x + 1;
3 | }
4 |
5 | function decrement(x){
6 | return x - 1;
7 | }
8 |
9 | function doAction(actionName){
10 | switch(actionName){
11 | case "increment":
12 | number = increment(number);
13 | break;
14 | case "decrement":
15 | number = decrement(number);
16 | break;
17 | }
18 | }
19 |
20 | let number = 0;
21 | doAction('increment')
22 | console.log(number)
--------------------------------------------------------------------------------
/CH 06 Statements/ternary.js:
--------------------------------------------------------------------------------
1 | const n = 3;
2 | let isEven = (n % 2 === 0)
3 | ? true
4 | : false;
5 |
6 | console.log(isEven);
7 |
8 | function getPrice(product){
9 | return product
10 | ? product.price
11 | ? product.price
12 | : product.lastPrice
13 | : null
14 | }
15 |
16 | console.log(getPrice(null));
17 | console.log(getPrice({lastPrice: 10}));
18 | console.log(getPrice({price:5, lastPrice: 10}));
--------------------------------------------------------------------------------
/CH 06 Statements/var.js:
--------------------------------------------------------------------------------
1 | var number = 1;
2 | console.log(number);
--------------------------------------------------------------------------------
/CH 06 Statements/while.js:
--------------------------------------------------------------------------------
1 | let i = 1;
2 |
3 | // eslint-disable-next-line functional/no-loop-statement
4 | while(i < 10){
5 | console.log(i);
6 | i = i + 1;
7 | }
--------------------------------------------------------------------------------
/CH 07 Recursion/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 07 Recursion/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "globals": {
7 | },
8 | "parserOptions": {
9 | "ecmaVersion": 11,
10 | "sourceType": "module"
11 | },
12 | "plugins": [
13 | "functional"
14 | ],
15 | "rules": {
16 | "functional/no-this-expression": "error",
17 | "functional/immutable-data": "error",
18 | "no-var": "error",
19 | "functional/no-conditional-statement": ["error", {
20 | "allowReturningBranches": "ifExhaustive"
21 | }],
22 | "functional/no-loop-statement": "error",
23 | "functional/no-throw-statement": "error"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/CH 07 Recursion/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 07 Recursion/factorial-conditional.js:
--------------------------------------------------------------------------------
1 | function factorial(n) {
2 | return (n === 0)
3 | ? 1
4 | : n * factorial(n - 1);
5 | }
6 |
7 | console.log(factorial(5));
--------------------------------------------------------------------------------
/CH 07 Recursion/factorial-recursive.js:
--------------------------------------------------------------------------------
1 | function factorial(n) {
2 | if (n === 0) {
3 | return 1;
4 | }
5 | else {
6 | return n * factorial(n - 1);
7 | }
8 | }
9 |
10 | console.log(factorial(5));
--------------------------------------------------------------------------------
/CH 07 Recursion/factorial-tc.js:
--------------------------------------------------------------------------------
1 | function factorial(n, result = 1) {
2 | //console.log(`n=${n}, result=${result}`);
3 |
4 | return (n === 0)
5 | ? result
6 | : factorial(n - 1, n * result);
7 | }
8 |
9 | console.log(factorial(5));
--------------------------------------------------------------------------------
/CH 07 Recursion/factorial.js:
--------------------------------------------------------------------------------
1 | function factorial(n) {
2 | let result = 1;
3 |
4 | let i = 2;
5 | while(i <= n){
6 | result = result * i;
7 | console.log(`i=${i}, result=${result}`);
8 | i = i + 1;
9 | }
10 |
11 | return result;
12 | }
13 |
14 | console.log(factorial(5));
--------------------------------------------------------------------------------
/CH 07 Recursion/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2"
15 | },
16 | "devDependencies": {
17 | "eslint": "^7.1.0",
18 | "eslint-plugin-functional": "^3.0.1"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/CH 07 Recursion/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node filter.js
--------------------------------------------------------------------------------
/CH 07 Recursion/stack-overflow-loop.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cristi-salcescu/functional-programming-in-javascript/30775e7a0cbd55323a12553aea568cdfa840f557/CH 07 Recursion/stack-overflow-loop.js
--------------------------------------------------------------------------------
/CH 07 Recursion/stack-overflow.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cristi-salcescu/functional-programming-in-javascript/30775e7a0cbd55323a12553aea568cdfa840f557/CH 07 Recursion/stack-overflow.js
--------------------------------------------------------------------------------
/CH 07 Recursion/sum-loop.js:
--------------------------------------------------------------------------------
1 | function sumAll(n) {
2 | let total = 0;
3 | let i = 1;
4 | while(i <= n){
5 | total = total + i;
6 | i = i + 1;
7 | }
8 |
9 | return total;
10 | }
11 |
12 | console.log(sumAll(10000));
--------------------------------------------------------------------------------
/CH 07 Recursion/sum-recursive.js:
--------------------------------------------------------------------------------
1 | function sumAll(n, i = 0, result = 0) {
2 | return (i > n)
3 | ? result
4 | : sumAll(n, i + 1, i + result);
5 | }
6 |
7 | console.log(sumAll(10000));
--------------------------------------------------------------------------------
/CH 07 Recursion/trampoline.js:
--------------------------------------------------------------------------------
1 | function sumAll(n, i = 0, result = 0) {
2 | return (i > n)
3 | ? () => result
4 | : () => sumAll(n, i + 1, i + result);
5 | }
6 |
7 | const _sumAll = trampoline(sumAll)
8 |
9 | function trampoline(f) {
10 | return function(...args){
11 | let result = f(...args);
12 | while (typeof(result) === 'function'){
13 | result = result();
14 | }
15 |
16 | return result;
17 | }
18 | }
19 |
20 |
21 | console.log(_sumAll(10000));
--------------------------------------------------------------------------------
/CH 07 Recursion/tree.js:
--------------------------------------------------------------------------------
1 | const tree = {
2 | value: 0,
3 | checked: false,
4 | children: [{
5 | value: 1,
6 | checked: true,
7 | children: [{
8 | value: 11,
9 | checked: true,
10 | children: null
11 | }]
12 | }, {
13 | value: 2,
14 | checked: false,
15 | children: [{
16 | value: 22,
17 | checked: true,
18 | children: null
19 | },{
20 | value: 23,
21 | checked: true,
22 | children: null
23 | }]
24 | }]
25 | }
26 |
27 | function toChildTopSelection(selection, childNode){
28 | return selection.concat(getTopSelection(childNode));
29 | }
30 |
31 | function getTopSelection(node){
32 | return node.checked
33 | ? [node.value]
34 | : node.children !== null
35 | ? node.children.reduce(toChildTopSelection, [])
36 | : []
37 | }
38 |
39 | console.log(getTopSelection(tree));
--------------------------------------------------------------------------------
/CH 08 Pipelines/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 08 Pipelines/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "globals": {
7 | },
8 | "parserOptions": {
9 | "ecmaVersion": 11,
10 | "sourceType": "module"
11 | },
12 | "plugins": [
13 | "functional"
14 | ],
15 | "rules": {
16 | "functional/no-this-expression": "error",
17 | "functional/immutable-data": "error",
18 | "no-var": "error",
19 | "functional/no-conditional-statement": ["error", {
20 | "allowReturningBranches": "ifExhaustive"
21 | }],
22 | "functional/no-loop-statement": "error",
23 | "functional/no-throw-statement": "error"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/CH 08 Pipelines/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 08 Pipelines/chaining-2.js:
--------------------------------------------------------------------------------
1 | const debts = [
2 | {
3 | contractNo : 1,
4 | daysSinceLastPayment: 91,
5 | currency : 'EUR'
6 | },
7 | {
8 | contractNo : 2,
9 | daysSinceLastPayment: 35,
10 | currency : 'USD'
11 | },
12 | {
13 | contractNo : 3,
14 | daysSinceLastPayment: 45,
15 | currency : 'USD'
16 | }
17 | ]
18 |
19 | function getPriority(debt){
20 | const days = debt.daysSinceLastPayment;
21 | return days > 90
22 | ? 1
23 | : days > 60
24 | ? 2
25 | : 3
26 | }
27 |
28 | function toDebtView(debt){
29 | return {
30 | ...debt,
31 | priority : getPriority(debt)
32 | }
33 | }
34 |
35 | function isCurrency(currency){
36 | return function (debt){
37 | return debt.currency === currency;
38 | }
39 | }
40 |
41 | function logIdentity(value){
42 | console.log(value);
43 | return value;
44 | }
45 |
46 | debts
47 | .filter(isCurrency('EUR'))
48 | .map(toDebtView)
49 | .map(logIdentity)
--------------------------------------------------------------------------------
/CH 08 Pipelines/chaining-3.js:
--------------------------------------------------------------------------------
1 | const debts = [
2 | {
3 | contractNo : 1,
4 | daysSinceLastPayment: 91,
5 | currency : 'EUR'
6 | },
7 | {
8 | contractNo : 2,
9 | daysSinceLastPayment: 35,
10 | currency : 'USD'
11 | },
12 | {
13 | contractNo : 3,
14 | daysSinceLastPayment: 45,
15 | currency : 'USD'
16 | }
17 | ]
18 |
19 | function getPriority(debt){
20 | const days = debt.daysSinceLastPayment;
21 | return days > 90
22 | ? 1
23 | : days > 60
24 | ? 2
25 | : 3
26 | }
27 |
28 | function toDebtView(debt){
29 | return {
30 | ...debt,
31 | priority : getPriority(debt)
32 | }
33 | }
34 |
35 | function isCurrency(currencies){
36 | return function (debt){
37 | return currencies.includes(debt.currency);
38 | }
39 | }
40 |
41 | function logIdentity(value){
42 | console.log(value);
43 | return value;
44 | }
45 |
46 | debts
47 | .filter(isCurrency(['EUR', 'USD']))
48 | .map(toDebtView)
49 | .map(logIdentity)
--------------------------------------------------------------------------------
/CH 08 Pipelines/chaining.js:
--------------------------------------------------------------------------------
1 | const debts = [
2 | {
3 | contractNo : 1,
4 | daysSinceLastPayment: 91,
5 | currency : 'EUR'
6 | },
7 | {
8 | contractNo : 2,
9 | daysSinceLastPayment: 35,
10 | currency : 'USD'
11 | },
12 | {
13 | contractNo : 3,
14 | daysSinceLastPayment: 45,
15 | currency : 'USD'
16 | }
17 | ]
18 |
19 | function getPriority(debt){
20 | const days = debt.daysSinceLastPayment;
21 | return days > 90
22 | ? 1
23 | : days > 60
24 | ? 2
25 | : 3
26 | }
27 |
28 | function toDebtView(debt){
29 | return {
30 | ...debt,
31 | priority : getPriority(debt)
32 | }
33 | }
34 |
35 | function isEur(debt){
36 | return debt.currency === "EUR";
37 | }
38 |
39 | function logIdentity(value){
40 | console.log(value);
41 | return value;
42 | }
43 |
44 | debts
45 | .filter(isEur)
46 | .map(toDebtView)
47 | .map(logIdentity)
--------------------------------------------------------------------------------
/CH 08 Pipelines/currying-1.js:
--------------------------------------------------------------------------------
1 | const words = [
2 | 'ability',
3 | 'calculate',
4 | 'calendar',
5 | 'double',
6 | 'door'
7 | ];
8 |
9 | function startsWith(word, term){
10 | return word.startsWith(term);
11 | }
12 |
13 | function trace(value){
14 | console.log(value);
15 | return value;
16 | }
17 |
18 | words
19 | .filter(w => startsWith(w, 'a'))
20 | .forEach(trace);
--------------------------------------------------------------------------------
/CH 08 Pipelines/currying-2.js:
--------------------------------------------------------------------------------
1 | const words = [
2 | 'ability',
3 | 'calculate',
4 | 'calendar',
5 | 'double',
6 | 'door'
7 | ];
8 |
9 | function startsWith(term){
10 | return function(word){
11 | return word.startsWith(term);
12 | }
13 | }
14 |
15 | function trace(value){
16 | console.log(value);
17 | return value;
18 | }
19 |
20 | words
21 | .filter(startsWith('a'))
22 | .forEach(trace);
--------------------------------------------------------------------------------
/CH 08 Pipelines/currying-3.js:
--------------------------------------------------------------------------------
1 | const words = [
2 | 'ability',
3 | 'calculate',
4 | 'calendar',
5 | 'double',
6 | 'door'
7 | ];
8 |
9 | const startsWith = term => word => {
10 | return word.startsWith(term);
11 | }
12 |
13 | function trace(value){
14 | console.log(value);
15 | return value;
16 | }
17 |
18 | words
19 | .filter(startsWith('a'))
20 | .forEach(trace);
--------------------------------------------------------------------------------
/CH 08 Pipelines/currying-4.js:
--------------------------------------------------------------------------------
1 | import { curry } from 'lodash/fp';
2 |
3 | const words = [
4 | 'ability',
5 | 'calculate',
6 | 'calendar',
7 | 'double',
8 | 'door'
9 | ];
10 |
11 | const startsWith = curry(function(term, word) {
12 | return word.startsWith(term);
13 | });
14 |
15 | function trace(value){
16 | console.log(value);
17 | return value;
18 | }
19 |
20 | words
21 | .filter(startsWith('a'))
22 | .forEach(trace);
--------------------------------------------------------------------------------
/CH 08 Pipelines/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2",
15 | "lodash": "^4.17.15"
16 | },
17 | "devDependencies": {
18 | "eslint": "^7.1.0",
19 | "eslint-plugin-functional": "^3.0.1"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/CH 08 Pipelines/pipe-weather.js:
--------------------------------------------------------------------------------
1 | import { pipe } from 'lodash/fp';
2 |
3 | function toCelsius(kelvin){
4 | return 300 - kelvin;
5 | }
6 |
7 | function describeTemperature(temperature){
8 | return temperature < 0
9 | ? "Freezing"
10 | : temperature < 15
11 | ? "Cold"
12 | : temperature < 28
13 | ? "Warm"
14 | : "Hot";
15 | }
16 |
17 | const temperatureDescription = pipe(
18 | toCelsius,
19 | describeTemperature
20 | )(273);
21 |
22 | console.log(temperatureDescription);
--------------------------------------------------------------------------------
/CH 08 Pipelines/pipe.js:
--------------------------------------------------------------------------------
1 | import { pipe } from 'lodash/fp';
2 |
3 | function capitalize(text) {
4 | return text.charAt(0).toUpperCase() + text.slice(1);
5 | }
6 |
7 | function shortenText(text) {
8 | return text.substring(0, 8).trim();
9 | }
10 |
11 | const shortText = shortenText(capitalize("this is a long text"));
12 | console.log(shortText);
13 | //"This is"
14 |
15 | const shortText1 = pipe(
16 | capitalize,
17 | shortenText
18 | )("this is a long text");
19 | console.log(shortText1);
20 | //"This is"
--------------------------------------------------------------------------------
/CH 08 Pipelines/reduce.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cristi-salcescu/functional-programming-in-javascript/30775e7a0cbd55323a12553aea568cdfa840f557/CH 08 Pipelines/reduce.js
--------------------------------------------------------------------------------
/CH 08 Pipelines/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node pipe.js
--------------------------------------------------------------------------------
/CH 09 Functors/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 09 Functors/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "extends": "eslint:recommended",
7 | "globals": {
8 | },
9 | "parserOptions": {
10 | "ecmaVersion": 11,
11 | "sourceType": "module"
12 | },
13 | "rules": {
14 | "functional/no-this-expression": "error",
15 | "functional/immutable-data": "error",
16 | "no-var": "error",
17 | "functional/no-conditional-statement": ["error", {
18 | "allowReturningBranches": "ifExhaustive"
19 | }],
20 | "functional/no-loop-statement": "error",
21 | "functional/no-throw-statement": "error"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CH 09 Functors/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 09 Functors/F.js:
--------------------------------------------------------------------------------
1 | function F(value){
2 |
3 | function map(f){
4 | const newValue = f(value);
5 | return F(newValue);
6 | }
7 |
8 | return {
9 | map
10 | }
11 | }
12 |
13 | export default F;
14 |
--------------------------------------------------------------------------------
/CH 09 Functors/array.js:
--------------------------------------------------------------------------------
1 | function increment(n){
2 | return n + 1;
3 | }
4 |
5 | function double(n){
6 | return n * 2
7 | }
8 |
9 | function identity(n){
10 | return n;
11 | }
12 |
13 | function logIdentity(value){
14 | console.log(value);
15 | return value;
16 | }
17 |
18 | [1, 2, 3]
19 | .map(identity)
20 | .map(logIdentity);
21 | //1
22 | //2
23 | //3
24 |
25 | [1, 2, 3]
26 | .map(increment)
27 | .map(double)
28 | .map(logIdentity);
29 | //4
30 | //6
31 | //8
32 |
33 | [1, 2, 3]
34 | .map(x => double(increment(x)))
35 | .map(logIdentity);
36 | //4
37 | //6
38 | //8
--------------------------------------------------------------------------------
/CH 09 Functors/array_weather.js:
--------------------------------------------------------------------------------
1 | import { compose } from 'lodash/fp'
2 |
3 | function toCelsius(kelvin){
4 | const celsius = (kelvin - 273.15);
5 | return Math.round(celsius * 100) / 100;
6 | }
7 |
8 | function describeTemperature(temperature){
9 | return temperature < 0
10 | ? "Freezing"
11 | : temperature < 15
12 | ? "Cold"
13 | : temperature < 28
14 | ? "Warm"
15 | : "Hot";
16 | }
17 |
18 | function logIdentity(value){
19 | console.log(value);
20 | return value;
21 | }
22 |
23 | [300]
24 | .map(toCelsius)
25 | .map(describeTemperature)
26 | .map(logIdentity);
27 |
28 | [300]
29 | .map(x => describeTemperature(toCelsius(x)))
30 | .map(logIdentity);
31 |
32 | [300]
33 | .map(compose(describeTemperature, toCelsius))
34 | .map(logIdentity);
--------------------------------------------------------------------------------
/CH 09 Functors/mapping.js:
--------------------------------------------------------------------------------
1 | function toCelsius(kelvin){
2 | const celsius = (kelvin - 273.15);
3 | return Math.round(celsius * 100) / 100;
4 | }
5 |
6 | function describeTemperature(temperature){
7 | return temperature < 0
8 | ? "Freezing"
9 | : temperature < 15
10 | ? "Cold"
11 | : temperature < 28
12 | ? "Warm"
13 | : "Hot";
14 | }
15 |
16 | const kelvin = 300;
17 | const celsius = toCelsius(kelvin);
18 | const description = describeTemperature(celsius);
19 |
20 | console.log(celsius);
21 | //26.85
22 | console.log(description)
23 | //"Warm"
--------------------------------------------------------------------------------
/CH 09 Functors/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2",
15 | "lodash": "^4.17.15"
16 | },
17 | "devDependencies": {
18 | "eslint": "^7.1.0"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/CH 09 Functors/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node F.js
--------------------------------------------------------------------------------
/CH 09 Functors/test_F.js:
--------------------------------------------------------------------------------
1 | import F from './F';
2 |
3 | function increment(n){
4 | return n + 1;
5 | }
6 |
7 | function double(n){
8 | return n * 2
9 | }
10 |
11 | function identity(n){
12 | return n;
13 | }
14 |
15 | function logIdentity(value){
16 | console.log(value);
17 | return value;
18 | }
19 |
20 | //identity laws
21 | F(1).map(identity).map(logIdentity);
22 |
23 | //composition laws
24 | F(1).map(increment).map(double).map(logIdentity);
25 | F(1).map(n => double(increment(n))).map(logIdentity);
26 |
27 | //chain
28 | F(1)
29 | .map(increment)
30 | .map(increment)
31 | .map(double)
32 | .map(logIdentity)
--------------------------------------------------------------------------------
/CH 09 Functors/test_F_weather.js:
--------------------------------------------------------------------------------
1 | import F from './F';
2 | import { compose } from 'lodash/fp'
3 |
4 | function toCelsius(kelvin){
5 | const celsius = (kelvin - 273.15);
6 | return Math.round(celsius * 100) / 100;
7 | }
8 |
9 | function describeTemperature(temperature){
10 | return temperature < 0
11 | ? "Freezing"
12 | : temperature < 15
13 | ? "Cold"
14 | : temperature < 28
15 | ? "Warm"
16 | : "Hot";
17 | }
18 |
19 | function logIdentity(value){
20 | console.log(value);
21 | return value;
22 | }
23 |
24 | F(300)
25 | .map(toCelsius)
26 | .map(describeTemperature)
27 | .map(logIdentity)
28 |
29 | F(300)
30 | .map(x => describeTemperature(toCelsius(x)))
31 | .map(logIdentity)
32 |
33 | F(300)
34 | .map(compose(describeTemperature, toCelsius))
35 | .map(logIdentity)
--------------------------------------------------------------------------------
/CH 10 Monads/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 10 Monads/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "extends": "eslint:recommended",
7 | "globals": {
8 | },
9 | "parserOptions": {
10 | "ecmaVersion": 11,
11 | "sourceType": "module"
12 | },
13 | "rules": {
14 | "functional/no-this-expression": "error",
15 | "functional/immutable-data": "error",
16 | "no-var": "error",
17 | "functional/no-conditional-statement": ["error", {
18 | "allowReturningBranches": "ifExhaustive"
19 | }],
20 | "functional/no-loop-statement": "error",
21 | "functional/no-throw-statement": "error"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CH 10 Monads/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 10 Monads/Applicative.js:
--------------------------------------------------------------------------------
1 | function M(value){
2 |
3 | function map(f){
4 | const newValue = f(value);
5 | return M(newValue);
6 | }
7 |
8 | function ap(otherMonad){
9 | const f = value;//The value must be a function
10 | const newValue = otherMonad.map(f);
11 | return newValue;
12 | }
13 |
14 | return {
15 | map,
16 | ap
17 | }
18 | }
19 |
20 | function logIdentity(n){
21 | console.log(n);
22 | return n;
23 | }
24 |
25 |
26 | function add(x){
27 | return function(y){
28 | return x + y;
29 | }
30 | }
31 |
32 | M(1)
33 | .map(add) //The value is now a function
34 | .ap(M(2))
35 | .map(logIdentity)
36 |
37 | M(2)
38 | .map(add) //The value is now a function
39 | .ap(M(1))
40 | .map(logIdentity)
41 |
42 | function multiply(x){
43 | return function(y){
44 | return function(z){
45 | return x * y * z;
46 | }
47 | }
48 | }
49 |
50 | M(2)
51 | .map(multiply) //The value is now a function
52 | .ap(M(3)) //The value is still a function
53 | .ap(M(4))
54 | .map(logIdentity)
--------------------------------------------------------------------------------
/CH 10 Monads/M-bind.js:
--------------------------------------------------------------------------------
1 | export default (function defineMonad(){
2 | function M(value){
3 | function map(f){
4 | const newValue = f(value);
5 | return M(newValue);
6 | }
7 |
8 | function bind(f){
9 | const newValue = f(value);
10 | return newValue;
11 | }
12 |
13 | return {
14 | map,
15 | bind
16 | }
17 | }
18 |
19 | function unit(value){
20 | return M(value);
21 | }
22 |
23 | return {
24 | unit
25 | }
26 | })();
--------------------------------------------------------------------------------
/CH 10 Monads/M.js:
--------------------------------------------------------------------------------
1 | function M(value){
2 |
3 | function map(f){
4 | const newValue = f(value);
5 | return M(newValue);
6 | }
7 |
8 | function flatMap(f){
9 | const newValue = f(value);
10 | return newValue;
11 | }
12 |
13 | return {
14 | map,
15 | flatMap
16 | }
17 | }
18 |
19 |
20 | export default M;
--------------------------------------------------------------------------------
/CH 10 Monads/Maybe.js:
--------------------------------------------------------------------------------
1 | function Maybe(value){
2 |
3 | function map(f){
4 | if (!value) {
5 | return Maybe(null);
6 | }
7 |
8 | const newValue = f(value);
9 | return Maybe(newValue);
10 | }
11 |
12 | function flatMap(f){
13 | const newValue = f(value);
14 | return newValue;
15 | }
16 |
17 | return {
18 | map,
19 | flatMap
20 | }
21 | }
22 |
23 |
24 | function prop(name){
25 | return function(obj){
26 | return obj[name];
27 | }
28 | }
29 |
30 | const book = {
31 | name: "Mastering JavaScript Functional Programming",
32 | author: {
33 | name: "Federico Kereki"
34 | }
35 | }
36 |
37 | const author = prop("author")(book);
38 | const name = prop("name")(author);
39 | console.log(name);
40 | //"Federico Kereki"
41 |
42 | Maybe(book)
43 | .map(prop("author"))
44 | .map(prop("name"))
45 | .flatMap(console.log)
46 |
47 | const book2 = {
48 | name: "JavaScript: The Good Parts",
49 | author: null
50 | }
51 |
52 | Maybe(book2)
53 | .map(prop("author"))
54 | .map(prop("name"))
55 | .flatMap(console.log)
56 |
--------------------------------------------------------------------------------
/CH 10 Monads/flat.js:
--------------------------------------------------------------------------------
1 | const arr = [1, [2, 3]];
2 |
3 | console.log(arr);
4 | console.log(arr.flat());
5 | //[ 1, 2, 3 ]
6 |
7 | function split(text){
8 | return text.split(' ');
9 | }
10 |
11 | const newArray = ["raspberry strawberry", "blueberry"]
12 | .map(split)
13 | .flat();
14 |
15 | console.log(newArray);
16 | //[ 'raspberry', 'strawberry', 'blueberry' ]
--------------------------------------------------------------------------------
/CH 10 Monads/flatMap.js:
--------------------------------------------------------------------------------
1 | function split(text){
2 | return text.split(' ');
3 | }
4 |
5 | const arr2 = ["raspberry strawberry", "blueberry"]
6 | .flatMap(split)
7 |
8 | console.log(arr2);
9 | //[ 'raspberry', 'strawberry', 'blueberry' ]
--------------------------------------------------------------------------------
/CH 10 Monads/map.js:
--------------------------------------------------------------------------------
1 | function toUpperCase(text){
2 | return text.toUpperCase();
3 | }
4 |
5 | const arr1 = ["raspberry strawberry", "blueberry"]
6 | .map(toUpperCase);
7 | console.log(arr1);
8 | //[ 'RASPBERRY STRAWBERRY', 'BLUEBERRY' ]
9 |
10 | function split(text){
11 | return text.split(' ');
12 | }
13 |
14 | const arr2 = ["raspberry strawberry", "blueberry"]
15 | .map(split)
16 |
17 | console.log(arr2);
18 | //[ [ 'raspberry', 'strawberry' ], [ 'blueberry' ] ]
--------------------------------------------------------------------------------
/CH 10 Monads/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2"
15 | },
16 | "devDependencies": {
17 | "eslint": "^7.1.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/CH 10 Monads/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node M.js
--------------------------------------------------------------------------------
/CH 10 Monads/test_Array_laws.js:
--------------------------------------------------------------------------------
1 | function M(n){
2 | return [n];
3 | }
4 |
5 | function duplicate(word){
6 | return [word, word]
7 | }
8 |
9 | function split(text){
10 | return text.split(" ");
11 | }
12 |
13 | //Left identity: M(x).flatMap(f) === f(x)
14 | const w = Array.of('mango')
15 | .flatMap(duplicate)
16 | //['mango', 'mango']
17 | console.log(w)
18 |
19 | console.log(duplicate('mango'));
20 | //['mango', 'mango']
21 |
22 | //Right identity: m.flatMap(M) === m
23 | const z = M('lemon')
24 | .flatMap(M)
25 | //['lemon']
26 | console.log(z)
27 |
28 | //Associativity
29 | const y = M('orange kiwi')
30 | .flatMap(split)
31 | .flatMap(duplicate);
32 | //[ 'orange', 'orange', 'kiwi', 'kiwi' ]
33 |
34 | const x = M('orange kiwi')
35 | .flatMap(s => split(s).flatMap(duplicate))
36 | //[ 'orange', 'orange', 'kiwi', 'kiwi' ]
37 | console.log(x)
38 | console.log(y)
39 |
--------------------------------------------------------------------------------
/CH 10 Monads/test_M.js:
--------------------------------------------------------------------------------
1 | import M from './M';
2 |
3 | function logIdentity(n){
4 | console.log(n);
5 | return n;
6 | }
7 |
8 | function incrementAsM(n){
9 | return M(n+1)
10 | }
11 |
12 | M(1)
13 | .flatMap(incrementAsM)
14 | .map(logIdentity)
15 | //M(2)
16 |
--------------------------------------------------------------------------------
/CH 10 Monads/test_M_bind.js:
--------------------------------------------------------------------------------
1 | import M from './M-bind';
2 |
3 | function logIdentity(n){
4 | console.log(n);
5 | return n;
6 | }
7 |
8 | function f(){
9 | return M.unit(2)
10 | }
11 |
12 | function g(){
13 | return M.unit(3)
14 | }
15 |
16 | //1. bind(unit(x), f) ≡ f(x)
17 | M.unit(1)
18 | .bind(f)
19 | .map(logIdentity)
20 | //M 2
21 |
22 | //2. bind(m, unit) ≡ m
23 |
24 | M.unit(1)
25 | .bind(M.unit)
26 | .map(logIdentity)
27 | //M 1
28 |
29 | //3. bind(bind(m, f), g) ≡ bind(m, x ⇒ bind(f(x), g))
30 |
31 | M.unit(1)
32 | .bind(f)
33 | .bind(g)
34 | .map(logIdentity)
35 | //M 3
36 |
37 | M.unit(1)
38 | .bind(x => f(x).bind(g))
39 | .map(logIdentity)
--------------------------------------------------------------------------------
/CH 10 Monads/test_M_laws.js:
--------------------------------------------------------------------------------
1 | import M from './M';
2 |
3 | function f(){
4 | return M(2)
5 | }
6 |
7 | function g(){
8 | return M(3)
9 | }
10 |
11 | function logIdentity(n){
12 | console.log(n);
13 | return n;
14 | }
15 |
16 | //Left identity: M(x).flatMap(f) === f(x)
17 | M(1)
18 | .flatMap(f)
19 | .map(logIdentity);
20 | //M(2)
21 |
22 | f(1)
23 | //M(2)
24 |
25 | //Right identity: m.flatMap(M) === m
26 | M(1)
27 | .flatMap(M)
28 | .map(logIdentity);
29 | //M(1)
30 |
31 | //Associativity
32 | M(1)
33 | .flatMap(f)
34 | .flatMap(g)
35 | .map(logIdentity)
36 | //M(3)
37 |
38 | M(1)
39 | .flatMap(n => f(n).flatMap(g))
40 | .map(logIdentity)
41 | //M(3)
--------------------------------------------------------------------------------
/CH 11 Immutable Collections/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 11 Immutable Collections/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "globals": {
7 | },
8 | "parserOptions": {
9 | "ecmaVersion": 11,
10 | "sourceType": "module"
11 | },
12 | "plugins": [
13 | "functional"
14 | ],
15 | "rules": {
16 | "functional/no-this-expression": "error",
17 | "functional/immutable-data": "error",
18 | "no-var": "error",
19 | "functional/no-conditional-statement": ["error", {
20 | "allowReturningBranches": "ifExhaustive"
21 | }],
22 | "functional/no-loop-statement": "error",
23 | "functional/no-throw-statement": "error"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/CH 11 Immutable Collections/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 11 Immutable Collections/List-Operations.js:
--------------------------------------------------------------------------------
1 | import { List } from 'immutable';
2 |
3 | const list = List([
4 | { name: 'Cascais', country: 'Portugal'},
5 | { name: 'Sintra ', country: 'Portugal' },
6 | { name: 'Nerja ', country: 'Spain' },
7 | ]);
8 |
9 | function inCountry(country){
10 | return function(destination){
11 | return destination.country === country;
12 | }
13 | }
14 |
15 | list
16 | .filter(inCountry('Portugal'))
17 | //List [{ name: 'Cascais', country: 'Portugal' },
18 | // { name: 'Sintra ', country: 'Portugal' }]
19 |
20 | const destination = list.find(inCountry('Portugal'));
21 | console.log(destination)
22 | //{ name: 'Cascais', country: 'Portugal' }
23 |
24 | const otherDestination = list.findLast(inCountry('Portugal'));
25 | console.log(otherDestination);
26 | //{ name: 'Sintra ', country: 'Portugal' }
--------------------------------------------------------------------------------
/CH 11 Immutable Collections/List.js:
--------------------------------------------------------------------------------
1 | import { List } from 'immutable';
2 |
3 | const emptyList = List();
4 | console.log(emptyList);
5 | // List []
6 |
7 | const list = List([
8 | { name: 'Rhodes' },
9 | { name: 'Malaga' }
10 | ]);
11 | console.log(list)
12 | // List [{ name: 'Rhodes' }, { name: 'Malaga' }]
13 |
14 | //Editing
15 | const newList = list.set(0, { name: 'Riomaggiore' });
16 | console.log(newList)
17 | // List [{ name: 'Riomaggiore' }, { name: 'Malaga' }]
18 | console.log(list === newList);
19 | //false
20 |
21 | //Adding
22 | const newList2 = list.push({name: 'Funchal'});
23 | console.log(newList2)
24 | // List [{ name: 'Rhodes' }, { name: 'Malaga' }, { name: 'Funchal' }]
25 |
26 | const newList3 = list.concat([{name: 'Funchal'}]);
27 | console.log(newList3)
28 | // List [{ name: 'Rhodes' }, { name: 'Malaga' }, { name: 'Funchal' }]
29 |
30 |
31 | //Deleting
32 | const newList4 = list.delete(0);
33 | console.log(newList4)
34 | // List [{ name: 'Malaga' }]
35 |
36 |
37 | //Clear
38 | const newList5 = list.clear();
39 | console.log(newList5)
40 | // List []
--------------------------------------------------------------------------------
/CH 11 Immutable Collections/Map-Operations.js:
--------------------------------------------------------------------------------
1 | import { Map } from 'immutable';
2 |
3 | function logIdentity(x){
4 | console.log(x);
5 | return x
6 | }
7 |
8 | Map({ a: 1, b: 2 })
9 | .map(x => 10 * x)
10 | .map(logIdentity)
11 |
12 | const x = Map({ a: 1, b: 2, c:3, d:4 })
13 | .filter(x => x%2 === 0)
14 | .map(logIdentity)
15 |
16 | console.log(x)
--------------------------------------------------------------------------------
/CH 11 Immutable Collections/Map.js:
--------------------------------------------------------------------------------
1 | import { Map } from 'immutable';
2 |
3 | const countryMap = Map({
4 | "1": { name: 'Italy'},
5 | "2": { name: 'Portugal'},
6 | "3": { name: 'UK'}
7 | });
8 | console.log(countryMap);
9 |
10 | console.log(countryMap.get("3"));
11 | //{ name: 'UK' }
12 |
13 | const newMap = countryMap.set("2", { name: 'Spain'});
14 | console.log(newMap.get("2"));
15 | //{ name: 'Spain' }
16 |
17 | const newMap2 = countryMap.delete("3");
18 | console.log(newMap2.has("3"));
19 | //false
20 | console.log(newMap2.get("3"));
21 | //undefined
22 |
--------------------------------------------------------------------------------
/CH 11 Immutable Collections/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2",
15 | "immutable": "^4.0.0-rc.12",
16 | "ramda": "^0.27.0"
17 | },
18 | "devDependencies": {
19 | "eslint": "^7.1.0",
20 | "eslint-plugin-functional": "^3.0.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/CH 11 Immutable Collections/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node List.js
--------------------------------------------------------------------------------
/CH 12 Lazy/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 12 Lazy/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "globals": {
7 | },
8 | "parserOptions": {
9 | "ecmaVersion": 11,
10 | "sourceType": "module"
11 | },
12 | "plugins": [
13 | "functional"
14 | ],
15 | "rules": {
16 | "functional/no-this-expression": "error",
17 | "functional/immutable-data": "error",
18 | "no-var": "error",
19 | "functional/no-conditional-statement": ["error", {
20 | "allowReturningBranches": "ifExhaustive"
21 | }],
22 | "functional/no-loop-statement": "error",
23 | "functional/no-throw-statement": "error"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/CH 12 Lazy/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 12 Lazy/Range.js:
--------------------------------------------------------------------------------
1 | import { Range } from 'immutable';
2 |
3 | function logIdentity(n){
4 | console.log(n);
5 | return n;
6 | }
7 |
8 | Range(1, 4)
9 | .forEach(logIdentity);
10 |
11 |
12 |
--------------------------------------------------------------------------------
/CH 12 Lazy/Seq.js:
--------------------------------------------------------------------------------
1 | import { Seq } from 'immutable';
2 |
3 | function isEven(n){
4 | return n % 2 === 0;
5 | }
6 |
7 | function double(n){
8 | return n * 2;
9 | }
10 |
11 | function logIdentity(n){
12 | console.log(n);
13 | return n;
14 | }
15 |
16 | const sequence = Seq([ 1, 2, 3, 4])
17 | .filter(isEven)
18 | .map(double)
19 | .map(logIdentity);
20 |
21 | console.log(sequence);
22 |
23 | const newArray = sequence.toArray();
24 | console.log(newArray);
--------------------------------------------------------------------------------
/CH 12 Lazy/chain.js:
--------------------------------------------------------------------------------
1 | function isEven(n){
2 | return n % 2 === 0;
3 | }
4 |
5 | function double(n){
6 | return n * 2;
7 | }
8 |
9 | const numbers = [1, 2, 3, 4];
10 | const newNumbers =
11 | numbers
12 | .filter(isEven)
13 | .map(double);
14 | console.log(newNumbers);
--------------------------------------------------------------------------------
/CH 12 Lazy/filter.js:
--------------------------------------------------------------------------------
1 | function filter(test) {
2 | return function reducer(arr, value) {
3 | if (test(value)) {
4 | return [...arr, value]
5 | } else {
6 | return arr;
7 | }
8 | }
9 | }
10 |
11 | function isEven(n){
12 | return n % 2 === 0;
13 | }
14 |
15 | const numbers = [1 ,2 ,3 , 4];
16 | const newNumbers = numbers.reduce(filter(isEven), []);
17 | console.log(newNumbers);
--------------------------------------------------------------------------------
/CH 12 Lazy/find.js:
--------------------------------------------------------------------------------
1 | function find(test) {
2 | return function reducer(foundValue, value) {
3 | if (test(value) && !foundValue) {
4 | return value
5 | } else {
6 | return foundValue;
7 | }
8 | }
9 | }
10 |
11 | function isEven(n){
12 | return n % 2 === 0;
13 | }
14 |
15 | const numbers = [1, 2, 3, 4];
16 | const element = numbers.reduce(find(isEven), undefined);
17 | console.log(element);
--------------------------------------------------------------------------------
/CH 12 Lazy/map.js:
--------------------------------------------------------------------------------
1 | function map(transform) {
2 | return function reducer(arr, value) {
3 | const newValue = transform(value);
4 | return [...arr, newValue];
5 | }
6 | }
7 |
8 | function double(n){
9 | return n * 2;
10 | }
11 |
12 | const numbers = [1, 2, 3];
13 | const newNumbers = numbers.reduce(map(double), []);
14 | console.log(newNumbers);
--------------------------------------------------------------------------------
/CH 12 Lazy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2",
15 | "immutable": "^4.0.0-rc.12",
16 | "lodash": "^4.17.15"
17 | },
18 | "devDependencies": {
19 | "eslint": "^7.1.0",
20 | "eslint-plugin-functional": "^3.0.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/CH 12 Lazy/prime-2.js:
--------------------------------------------------------------------------------
1 | import { Range } from 'immutable';
2 |
3 | Range(0, 10)
4 | .filter(isPrime)
5 | .forEach(log);
6 |
7 | function log(number) {
8 | console.log(number);
9 | }
10 |
11 | function isPrime(number){
12 | if (number <= 1){
13 | return false;
14 | }
15 |
16 | for (let i=2; i<=number/2; i++)
17 | {
18 | if (number % i === 0 )
19 | return false;
20 | }
21 |
22 | return true;
23 | }
--------------------------------------------------------------------------------
/CH 12 Lazy/prime-3.js:
--------------------------------------------------------------------------------
1 | import { Range } from 'immutable';
2 |
3 | Range(0, 10)
4 | .filter(isPrime)
5 | .forEach(log);
6 |
7 | function isPrime(number) {
8 | if (number > 2){
9 | const firstDivisor = findFirstDivisor(number);
10 | return !firstDivisor;
11 | } else {
12 | return (number === 2)
13 | ? true
14 | : false;
15 | }
16 | }
17 |
18 | function findFirstDivisor(number){
19 | return Range(2, (number / 2) + 1)
20 | .find(isDivisorOf(number));
21 | }
22 |
23 | function isDivisorOf(number) {
24 | return function(divisor) {
25 | return (number > 1)
26 | ? number % divisor === 0
27 | : false
28 | };
29 | }
30 |
31 | function log(number) {
32 | console.log(number);
33 | }
--------------------------------------------------------------------------------
/CH 12 Lazy/prime.js:
--------------------------------------------------------------------------------
1 | function isPrime(number){
2 | if (number <= 1){
3 | return false;
4 | }
5 |
6 | for (let i=2; i<=number/2; i++)
7 | {
8 | if (number % i === 0 )
9 | return false;
10 | }
11 |
12 | return true;
13 | }
14 |
15 | for(let i=0; i<10; i++){
16 | if(isPrime(i)){
17 | console.log(i)
18 | }
19 | }
--------------------------------------------------------------------------------
/CH 12 Lazy/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node Sequence.js
--------------------------------------------------------------------------------
/CH 12 Lazy/transducer.js:
--------------------------------------------------------------------------------
1 | import { pipe, compose } from 'lodash/fp';
2 |
3 | function _filter(test) {
4 | return function(reducer){
5 | return function filterReducer(arr, value){
6 | if(test(value)){
7 | return reducer(arr, value);
8 | } else {
9 | return arr;
10 | }
11 | }
12 | }
13 | }
14 |
15 | const filter = test => reducer => {
16 | return function filterReducer(arr, value){
17 | return test(value)
18 | ? reducer(arr, value)
19 | : arr
20 | }
21 | }
22 |
23 | const map = transform => reducer => {
24 | return function mapReducer(arr, value){
25 | const newValue = transform(value);
26 | return reducer(arr, newValue);
27 | }
28 | }
29 |
30 | const toArrayReducer = (arr, value) => {
31 | return [...arr, value]
32 | };
33 |
34 | function isEven(n){
35 | return n % 2 === 0;
36 | }
37 |
38 | function double(n){
39 | return n * 2;
40 | }
41 |
42 | const numbers = [1 , 2, 3, 4];
43 |
44 | //
45 | const filterTransducer = filter(isEven);
46 | const mapTransducer = map(double);
47 |
48 | const newNumbers = numbers
49 | .reduce(filterTransducer(mapTransducer(toArrayReducer)), []);
50 | console.log(newNumbers);
51 |
52 | //
53 | const newReducer = compose(
54 | filter(isEven),
55 | map(double)
56 | )(toArrayReducer);
57 | console.log(numbers.reduce(newReducer, []));
--------------------------------------------------------------------------------
/CH 13 Generators/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 13 Generators/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "globals": {
7 | },
8 | "parserOptions": {
9 | "ecmaVersion": 11,
10 | "sourceType": "module"
11 | },
12 | "plugins": [
13 | "functional"
14 | ],
15 | "rules": {
16 | "functional/no-this-expression": "error",
17 | "functional/immutable-data": "error",
18 | "no-var": "error",
19 | "functional/no-conditional-statement": ["error", {
20 | "allowReturningBranches": "ifExhaustive"
21 | }],
22 | "functional/no-loop-statement": "error",
23 | "functional/no-throw-statement": "error"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/CH 13 Generators/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 13 Generators/fibonacci.js:
--------------------------------------------------------------------------------
1 | function fibonacci() {
2 | let a = 0;
3 | let b = 1;
4 | return function fibonacciGenerator() {
5 | const aResult = a;
6 | a = b;
7 | b = aResult + b;
8 | return aResult;
9 | };
10 | }
11 |
12 | export default fibonacci;
--------------------------------------------------------------------------------
/CH 13 Generators/forEach.js:
--------------------------------------------------------------------------------
1 | function forEach(callback){
2 | return function(generate){
3 | let value = generate();
4 | // eslint-disable-next-line functional/no-loop-statement
5 | while(value !== undefined){
6 | callback(value);
7 | value = generate();
8 | }
9 | }
10 |
11 | }
12 |
13 | export default forEach;
--------------------------------------------------------------------------------
/CH 13 Generators/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2",
15 | "immutable": "^4.0.0-rc.12",
16 | "lodash": "^4.17.15"
17 | },
18 | "devDependencies": {
19 | "eslint": "^7.1.0",
20 | "eslint-plugin-functional": "^3.0.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/CH 13 Generators/pipe.js:
--------------------------------------------------------------------------------
1 | import { pipe } from 'lodash/fp';
2 |
3 | function capitalize(text) {
4 | return text.charAt(0).toUpperCase() + text.slice(1);
5 | }
6 |
7 | function shortenText(text) {
8 | return text.substring(0, 8).trim();
9 | }
10 |
11 | const shortText = shortenText(capitalize("this is a long text"));
12 | console.log(shortText);
13 |
14 | const shortText1 = pipe(
15 | capitalize,
16 | shortenText
17 | )("this is a long text");
18 | console.log(shortText1);
--------------------------------------------------------------------------------
/CH 13 Generators/range-finite.js:
--------------------------------------------------------------------------------
1 | function range(from, to){
2 | let count = from;
3 | return function(){
4 | if(count < to){
5 | const result = count;
6 | count += 1;
7 | return result;
8 | } else {
9 | return undefined;
10 | }
11 | }
12 | }
13 |
14 | export default range;
--------------------------------------------------------------------------------
/CH 13 Generators/range.js:
--------------------------------------------------------------------------------
1 | function range() {
2 | let count = 0;
3 | return function rangeGenerator() {
4 | const result = count;
5 | count += 1;
6 | return result;
7 | }
8 | }
9 |
10 | export default range;
--------------------------------------------------------------------------------
/CH 13 Generators/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node sequence.js
--------------------------------------------------------------------------------
/CH 13 Generators/take.js:
--------------------------------------------------------------------------------
1 | function take(n) {
2 | return function(generate) {
3 | let count = 0;
4 | return function() {
5 | if (count < n) {
6 | count += 1;
7 | return generate();
8 | }
9 | };
10 | };
11 | }
12 |
13 | export default take;
--------------------------------------------------------------------------------
/CH 13 Generators/test_fibonacci.js:
--------------------------------------------------------------------------------
1 | import { pipe } from 'lodash/fp';
2 | import fibonacci from './fibonacci';
3 | import take from './take';
4 | import forEach from './forEach';
5 |
6 | const generateFibonacci = fibonacci();
7 | pipe(
8 | take(5),
9 | forEach(console.log)
10 | )(generateFibonacci);
11 | //0
12 | //1
13 | //1
14 | //2
15 | //3
--------------------------------------------------------------------------------
/CH 13 Generators/test_forEach.js:
--------------------------------------------------------------------------------
1 | import range from './range-finite';
2 | import forEach from './forEach';
3 |
4 | function log(x){
5 | console.log(x);
6 | }
7 |
8 | const nextNumber = range(1, 4);
9 | forEach(log)(nextNumber);
10 | //1
11 | //2
12 | //3
--------------------------------------------------------------------------------
/CH 13 Generators/test_range.js:
--------------------------------------------------------------------------------
1 | import range from './range';
2 |
3 | const nextNumber = range();
4 | console.log(nextNumber()); //0
5 | console.log(nextNumber()); //1
6 | console.log(nextNumber()); //2
--------------------------------------------------------------------------------
/CH 13 Generators/test_range_finite.js:
--------------------------------------------------------------------------------
1 | import range from './range-finite';
2 |
3 | const nextNumber = range(0, 3)
4 | console.log(nextNumber());
5 | console.log(nextNumber());
6 | console.log(nextNumber());
7 | console.log(nextNumber());
--------------------------------------------------------------------------------
/CH 13 Generators/test_range_take.js:
--------------------------------------------------------------------------------
1 | import { pipe } from 'lodash/fp';
2 | import range from './range';
3 | import take from './take';
4 | import forEach from './forEach';
5 |
6 | const nextNumber = range();
7 | pipe(
8 | take(3),
9 | forEach(console.log)
10 | )(nextNumber);
--------------------------------------------------------------------------------
/CH 13 Generators/test_toArray.js:
--------------------------------------------------------------------------------
1 | import range from './range-finite';
2 | import toArray from './toArray';
3 |
4 | const numbers = toArray(range(1, 5));
5 | console.log(numbers);
6 | //[1, 2, 3, 4]
--------------------------------------------------------------------------------
/CH 13 Generators/toArray.js:
--------------------------------------------------------------------------------
1 | function toArray(generate) {
2 | let arr = [];
3 | let value = generate();
4 | // eslint-disable-next-line functional/no-loop-statement
5 | while (value !== undefined) {
6 | arr = [...arr, value];
7 | value = generate();
8 | }
9 | return arr;
10 | }
11 |
12 | export default toArray;
--------------------------------------------------------------------------------
/CH 14 Promises AJAX/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 14 Promises AJAX/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "globals": {
7 | },
8 | "parserOptions": {
9 | "ecmaVersion": 11,
10 | "sourceType": "module"
11 | },
12 | "plugins": [
13 | "functional"
14 | ],
15 | "rules": {
16 | "functional/no-this-expression": "error",
17 | "functional/immutable-data": "error",
18 | "no-var": "error",
19 | "functional/no-conditional-statement": ["error", {
20 | "allowReturningBranches": "ifExhaustive"
21 | }],
22 | "functional/no-loop-statement": "error",
23 | "functional/no-throw-statement": "error"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/CH 14 Promises AJAX/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .cache
3 | node_modules
4 | dist
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/CH 14 Promises AJAX/all.js:
--------------------------------------------------------------------------------
1 | const dictionariesPromise = fetch('http://localhost:3000/dictionaries').then(toJson);
2 | const todosPromise = fetch('http://localhost:3000/todos').then(toJson);
3 |
4 | function logIdentity(x){
5 | console.log(x);
6 | return x;
7 | }
8 |
9 | function toJson(response){
10 | return response.json();
11 | }
12 |
13 | Promise.all([
14 | dictionariesPromise,
15 | todosPromise
16 | ]).then(logIdentity);
17 |
18 |
--------------------------------------------------------------------------------
/CH 14 Promises AJAX/allSettled.js:
--------------------------------------------------------------------------------
1 | const dictionariesPromise = fetch('http://localhost:3000/dictionaries').then(toJson);
2 | const todosPromise = fetch('http://localhost:3000/todos').then(toJson);
3 | const rejectedPromise = Promise.reject('Error');
4 |
5 | function toJson(response){
6 | return response.json();
7 | }
8 |
9 | function logIdentity(x){
10 | console.log(x);
11 | return x;
12 | }
13 |
14 | Promise.allSettled([
15 | dictionariesPromise,
16 | todosPromise,
17 | rejectedPromise
18 | ])
19 | .then(logIdentity)
20 | //[
21 | //{status: "fulfilled", value: Array(1)},
22 | //{status: "fulfilled", value: Array(1)},
23 | //{status: "rejected", reason: "Error"}
24 | //]
25 |
26 |
27 |
--------------------------------------------------------------------------------
/CH 14 Promises AJAX/fetch.js:
--------------------------------------------------------------------------------
1 | function toJson(response){
2 | return response.json();
3 | }
4 |
5 | function logIdentity(x){
6 | console.log(x);
7 | return x;
8 | }
9 |
10 | function logError(errorMsg){
11 | console.error(errorMsg);
12 | }
13 |
14 | fetch('https://api.github.ssscom/gists/public')
15 | .then(toJson)
16 | .then(logIdentity)
17 | .catch(logError);
--------------------------------------------------------------------------------
/CH 14 Promises AJAX/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/CH 14 Promises AJAX/insequence.js:
--------------------------------------------------------------------------------
1 | function fetchDictionaries(){
2 | return fetch('http://localhost:3000/dictionaries')
3 | .then(toJson);
4 | }
5 |
6 | function fetchTodos(){
7 | return fetch('http://localhost:3000/todos')
8 | .then(toJson);
9 | }
10 |
11 | function logIdentity(x){
12 | console.log(x);
13 | return x;
14 | }
15 |
16 | function toJson(response){
17 | return response.json();
18 | }
19 |
20 | fetchDictionaries()
21 | .then(fetchTodos)
22 | .then(logIdentity);
23 |
24 |
--------------------------------------------------------------------------------
/CH 14 Promises AJAX/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "observables",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "dev": "parcel index.html"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@babel/core": "^7.10.2",
14 | "@babel/node": "^7.10.1",
15 | "@babel/preset-env": "^7.10.2",
16 | "rxjs": "^6.5.5"
17 | },
18 | "devDependencies": {
19 | "eslint": "^7.1.0",
20 | "eslint-plugin-functional": "^3.0.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/CH 14 Promises AJAX/race.js:
--------------------------------------------------------------------------------
1 | const dictionariesPromise = fetch('http://localhost:3000/dictionaries').then(toJson);
2 | const todosPromise = fetch('http://localhost:3000/todos').then(toJson);
3 |
4 | function logIdentity(x){
5 | console.log(x);
6 | return x;
7 | }
8 |
9 | function toJson(response){
10 | return response.json();
11 | }
12 |
13 | Promise.race([
14 | dictionariesPromise,
15 | todosPromise
16 | ]).then(logIdentity);
17 |
18 |
--------------------------------------------------------------------------------
/CH 14 Promises AJAX/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node from.js
--------------------------------------------------------------------------------
/CH 14 Promises/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 14 Promises/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "globals": {
7 | },
8 | "parserOptions": {
9 | "ecmaVersion": 11,
10 | "sourceType": "module"
11 | },
12 | "plugins": [
13 | "functional"
14 | ],
15 | "rules": {
16 | "functional/no-this-expression": "error",
17 | "functional/immutable-data": "error",
18 | "no-var": "error",
19 | "functional/no-conditional-statement": ["error", {
20 | "allowReturningBranches": "ifExhaustive"
21 | }],
22 | "functional/no-loop-statement": "error",
23 | "functional/no-throw-statement": "error"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/CH 14 Promises/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 14 Promises/catch.js:
--------------------------------------------------------------------------------
1 | function devideBy(divisor){
2 | return function(number){
3 | const result = number / divisor;
4 | return (divisor !== 0)
5 | ? Promise.resolve(result)
6 | : Promise.reject("Can't divide by 0")
7 | }
8 | }
9 |
10 | function logIdentity(value){
11 | console.log(value);
12 | return value;
13 | }
14 |
15 | function logError(error){
16 | console.error(error);
17 | }
18 |
19 | Promise.resolve(9)
20 | .then(logIdentity)
21 | .then(devideBy(0))
22 | .then(logIdentity)
23 | .catch(logError)
--------------------------------------------------------------------------------
/CH 14 Promises/chain.js:
--------------------------------------------------------------------------------
1 | function toCelsius(kelvin){
2 | const celsius = (kelvin - 273.15);
3 | return Math.round(celsius * 100) / 100;
4 | }
5 |
6 | function toChangeAction(temperature){
7 | return {
8 | type : 'CHANGE_TEMPERATURE',
9 | temperature
10 | }
11 | }
12 |
13 | function logIdentity(value){
14 | console.log(value);
15 | return value;
16 | }
17 |
18 | Promise.resolve(280)
19 | .then(logIdentity)
20 | .then(toCelsius)
21 | .then(logIdentity)
22 | .then(toChangeAction)
23 | .then(logIdentity);
24 |
--------------------------------------------------------------------------------
/CH 14 Promises/delay.js:
--------------------------------------------------------------------------------
1 | function delay(interval){
2 | return new Promise(function(resolve){
3 | return setTimeout(resolve, interval);
4 | });
5 | }
6 |
7 | function logDone(){
8 | console.log('Done');
9 | }
10 |
11 | delay(1000)
12 | .then(logDone);
--------------------------------------------------------------------------------
/CH 14 Promises/flat-mapping-2.js:
--------------------------------------------------------------------------------
1 | function devideBy(divisor){
2 | return function(n){
3 | return n / divisor;
4 | }
5 | }
6 |
7 | function logIdentity(value){
8 | console.log(value);
9 | return value;
10 | }
11 |
12 | Promise.resolve(9)
13 | .then(logIdentity)
14 | .then(devideBy(3))
15 | .then(logIdentity);
--------------------------------------------------------------------------------
/CH 14 Promises/flat-mapping-3.js:
--------------------------------------------------------------------------------
1 | function devideBy(divisor){
2 | return function(number){
3 | const result = number / divisor;
4 | return Promise.resolve(result);
5 | }
6 | }
7 |
8 | function logIdentity(value){
9 | console.log(value);
10 | return value;
11 | }
12 |
13 | Promise.resolve(9)
14 | .then(logIdentity)
15 | .then(devideBy(3))
16 | .then(logIdentity);
--------------------------------------------------------------------------------
/CH 14 Promises/flat-mapping.js:
--------------------------------------------------------------------------------
1 | function devideBy(n, divisor){
2 | return n / divisor;
3 | }
4 |
5 | function logIdentity(value){
6 | console.log(value);
7 | return value;
8 | }
9 |
10 | Promise.resolve(9)
11 | .then(logIdentity)
12 | .then(n => devideBy(n, 3))
13 | .then(logIdentity);
--------------------------------------------------------------------------------
/CH 14 Promises/laws-functor-1.js:
--------------------------------------------------------------------------------
1 | //Identity Law
2 |
3 | function identity(n){
4 | return n;
5 | }
6 |
7 | Promise.resolve(1)
8 | .then(identity)
9 | //Promise 1
10 |
11 | //Composition Law
12 |
13 | function f(x){
14 | return x + 1;
15 | }
16 |
17 | function g(x){
18 | return x * 2;
19 | }
20 |
21 | function logIdentity(value){
22 | console.log(value);
23 | return value;
24 | }
25 |
26 | Promise.resolve(1)
27 | .then(f)
28 | .then(g)
29 | .then(logIdentity)
30 |
31 | Promise.resolve(1)
32 | .then(x => g(f(x)))
33 | .then(logIdentity)
34 |
35 |
--------------------------------------------------------------------------------
/CH 14 Promises/laws-functor-2.js:
--------------------------------------------------------------------------------
1 | function f(x){
2 | return Promise.resolve(x + 1);
3 | }
4 |
5 | function g(x){
6 | return x * 2;
7 | }
8 |
9 | function logIdentity(value){
10 | console.log(value);
11 | return value;
12 | }
13 |
14 | Promise.resolve(1)
15 | .then(f)
16 | .then(g)
17 | .then(logIdentity);
18 |
19 | Promise.resolve(1)
20 | .then(x => g(f(x)))
21 | .then(logIdentity);
22 |
23 | //It breaks the Functor Laws
24 |
25 |
26 |
--------------------------------------------------------------------------------
/CH 14 Promises/laws-monad-3.js:
--------------------------------------------------------------------------------
1 |
2 | //Left Identity
3 | //M(x).flatMap(f) === f(x)
4 |
5 | Promise.resolve(1)
6 | .then(f)
7 | .then(logIdentity);
8 | //Promise 2
9 |
10 | f(1)
11 | //Promise 2
12 |
13 | //Right Identity
14 | //monad.flatMap(M) === monad
15 |
16 | function unit(value){
17 | return Promise.resolve(value)
18 | }
19 |
20 | Promise.resolve(1)
21 | .then(unit)
22 | .then(logIdentity);
23 | //Promise 1
24 |
25 | //Associativity
26 | //m.flatMap(f).flatMap(g) ==== m.flatMap(x => f(x).flatMap(g))
27 |
28 | function f(x){
29 | return Promise.resolve(x + 1);
30 | }
31 |
32 | function g(x){
33 | return Promise.resolve(x * 2);
34 | }
35 |
36 | function logIdentity(value){
37 | console.log(value);
38 | return value;
39 | }
40 |
41 | Promise.resolve(1)
42 | .then(f)
43 | .then(g)
44 | .then(logIdentity);
45 |
46 | Promise.resolve(1)
47 | .then(x => f(x).then(g))
48 | .then(logIdentity);
49 |
50 |
--------------------------------------------------------------------------------
/CH 14 Promises/mappable.js:
--------------------------------------------------------------------------------
1 | function toUpperCase(text){
2 | return text.toUpperCase();
3 | }
4 |
5 | function logIdentity(value){
6 | console.log(value);
7 | return value;
8 | }
9 |
10 | Promise.resolve('sTudY')
11 | .then(logIdentity)
12 | .then(toUpperCase)
13 | .then(logIdentity);
--------------------------------------------------------------------------------
/CH 14 Promises/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2",
15 | "immutable": "^4.0.0-rc.12",
16 | "ramda": "^0.27.0"
17 | },
18 | "devDependencies": {
19 | "eslint": "^7.1.0",
20 | "eslint-plugin-functional": "^3.0.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/CH 14 Promises/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node list.js
--------------------------------------------------------------------------------
/CH 14 Promises/timeout.js:
--------------------------------------------------------------------------------
1 | function timeout(interval){
2 | return new Promise(function(resolve, reject){
3 | return setTimeout(reject, interval);
4 | });
5 | }
6 |
7 | function logFailed(){
8 | console.log('Failed');
9 | }
10 |
11 | timeout(1000)
12 | .catch(logFailed);
--------------------------------------------------------------------------------
/CH 15 Observables AJAX/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 15 Observables AJAX/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "globals": {
7 | },
8 | "parserOptions": {
9 | "ecmaVersion": 11,
10 | "sourceType": "module"
11 | },
12 | "plugins": [
13 | "functional"
14 | ],
15 | "rules": {
16 | "functional/no-this-expression": "error",
17 | "functional/immutable-data": "error",
18 | "no-var": "error",
19 | "functional/no-conditional-statement": ["error", {
20 | "allowReturningBranches": "ifExhaustive"
21 | }],
22 | "functional/no-loop-statement": "error",
23 | "functional/no-throw-statement": "error"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/CH 15 Observables AJAX/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .cache
3 | node_modules
4 | dist
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/CH 15 Observables AJAX/ajax.js:
--------------------------------------------------------------------------------
1 | import { ajax } from 'rxjs/ajax';
2 | import { map } from 'rxjs/operators';
3 |
4 | ajax('https://api.github.com/gists/public').subscribe(console.log);
5 |
6 | ajax('https://api.github.com/gists/public').pipe(
7 | map(data => data.response),
8 | ).subscribe(console.log);
9 |
10 | ajax.getJSON('https://api.github.com/gists/public')
11 | .subscribe(console.log);
--------------------------------------------------------------------------------
/CH 15 Observables AJAX/concatAll.js:
--------------------------------------------------------------------------------
1 | import { from } from 'rxjs';
2 | import { ajax } from 'rxjs/ajax';
3 | import { map, concatAll } from 'rxjs/operators';
4 |
5 | const observable = from([
6 | 'http://localhost:3000/dictionaries',
7 | 'http://localhost:3000/todos'
8 | ]);
9 |
10 | observable.pipe(
11 | map(ajax.getJSON),
12 | concatAll()
13 | ).subscribe(console.log);
14 | //[{name: 'Dictionary'}]
15 | //[{title: 'To Do'}]
16 |
--------------------------------------------------------------------------------
/CH 15 Observables AJAX/forkJoin.js:
--------------------------------------------------------------------------------
1 | import { ajax } from 'rxjs/ajax';
2 | import { forkJoin } from 'rxjs';
3 |
4 | const dictionariesObservable = ajax.getJSON('http://localhost:3000/dictionaries');
5 | const todosObservable = ajax.getJSON('http://localhost:3000/todos');
6 |
7 | forkJoin({
8 | dictionaries: dictionariesObservable,
9 | todos: todosObservable
10 | }
11 | )
12 | .subscribe(console.log);
13 | //{dictionaries: Array(), todos: Array()}
14 |
--------------------------------------------------------------------------------
/CH 15 Observables AJAX/hoo.js:
--------------------------------------------------------------------------------
1 | import { from } from 'rxjs';
2 | import { ajax } from 'rxjs/ajax';
3 | import { map } from 'rxjs/operators';
4 |
5 | const observable = from([
6 | 'http://localhost:3000/dictionaries',
7 | 'http://localhost:3000/todos'
8 | ]);
9 |
10 | observable.pipe(
11 | map(ajax.getJSON)
12 | ).subscribe(console.log);
13 |
--------------------------------------------------------------------------------
/CH 15 Observables AJAX/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CH 15 Observables AJAX/insequence.js:
--------------------------------------------------------------------------------
1 | import { map, mapTo, take, tap, concatAll } from 'rxjs/operators';
2 | import { interval } from 'rxjs';
3 |
4 | const obs1 = interval(10000).pipe(
5 | take(1),
6 | mapTo('1st')
7 | );
8 |
9 | const obs2 = interval(3000)
10 | .pipe(
11 | take(1),
12 | mapTo('2nd')
13 | );
14 |
15 | obs1
16 | .pipe(
17 | tap(console.log),
18 | //map(() => obs2),
19 | mapTo(obs2),
20 | concatAll()
21 | )
22 | .subscribe(console.log)
23 |
--------------------------------------------------------------------------------
/CH 15 Observables AJAX/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "observables",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "dev": "parcel index.html"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@babel/core": "^7.10.2",
14 | "@babel/node": "^7.10.1",
15 | "@babel/preset-env": "^7.10.2",
16 | "rxjs": "^6.5.5"
17 | },
18 | "devDependencies": {
19 | "eslint": "^7.1.0",
20 | "eslint-plugin-functional": "^3.0.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/CH 15 Observables AJAX/race.js:
--------------------------------------------------------------------------------
1 | import { ajax } from 'rxjs/ajax';
2 | import { race } from 'rxjs';
3 |
4 | const dictionariesObservable = ajax.getJSON('http://localhost:3000/dictionaries');
5 | const todosObservable = ajax.getJSON('http://localhost:3000/todos');
6 |
7 | //take the first observable to emit
8 | const observable = race(
9 | dictionariesObservable,
10 | todosObservable
11 | );
12 |
13 | observable.subscribe(console.log);
14 |
15 |
--------------------------------------------------------------------------------
/CH 15 Observables AJAX/run.bat:
--------------------------------------------------------------------------------
1 | npm run dev
--------------------------------------------------------------------------------
/CH 15 Observables/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/CH 15 Observables/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "globals": {
7 | },
8 | "parserOptions": {
9 | "ecmaVersion": 11,
10 | "sourceType": "module"
11 | },
12 | "plugins": [
13 | "functional"
14 | ],
15 | "rules": {
16 | "functional/no-this-expression": "error",
17 | "functional/immutable-data": "error",
18 | "no-var": "error",
19 | "functional/no-conditional-statement": ["error", {
20 | "allowReturningBranches": "ifExhaustive"
21 | }],
22 | "functional/no-loop-statement": "error",
23 | "functional/no-throw-statement": "error"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/CH 15 Observables/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/CH 15 Observables/combine.js:
--------------------------------------------------------------------------------
1 | import { of } from 'rxjs';
2 | import { map, filter } from 'rxjs/operators';
3 | import { timer, combineLatest } from 'rxjs';
4 |
5 | const dataSource1 = of(1, 2, 3, 4, 5);
6 | const dataSource2 = of('A', 'B', 'C');
7 |
8 | combineLatest(dataSource1, dataSource2)
9 | .subscribe(
10 | ([data1, data2]) => {
11 | console.log(data1)
12 | console.log(data2)
13 | }
14 | )
--------------------------------------------------------------------------------
/CH 15 Observables/create.js:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 |
3 | const observable = Observable.create(observer => {
4 | observer.next(1);
5 | observer.next(2);
6 | observer.next(3);
7 | observer.complete();
8 | });
9 |
10 | observable.subscribe(console.log);
11 |
12 | setTimeout(()=>{
13 | observable.subscribe(console.log);
14 | //1
15 | //2
16 | //3
17 | }, 3000);
--------------------------------------------------------------------------------
/CH 15 Observables/filter.js:
--------------------------------------------------------------------------------
1 | import { of } from 'rxjs';
2 | import { map, filter } from 'rxjs/operators';
3 |
4 | const dataSource = of(1, 2, 3, 4, 5);
5 |
6 | function isEven(n){
7 | return n % 2 === 0;
8 | }
9 |
10 | dataSource
11 | .pipe(
12 | filter(isEven)
13 | )
14 | .subscribe(console.log);
--------------------------------------------------------------------------------
/CH 15 Observables/from.js:
--------------------------------------------------------------------------------
1 | import { from } from 'rxjs';
2 |
3 | const observable = from([1, 2, 3]);
4 | observable.subscribe(console.log);
5 | // 1
6 | // 2
7 | // 3
--------------------------------------------------------------------------------
/CH 15 Observables/interval.js:
--------------------------------------------------------------------------------
1 | import { interval } from 'rxjs';
2 |
3 | /* number of milliseconds */
4 | const observable = interval(1000);
5 | observable.subscribe(console.log);
6 | //0
7 | //1
8 | //2
9 | //3
10 | //4
11 | //5
12 |
--------------------------------------------------------------------------------
/CH 15 Observables/laws1.js:
--------------------------------------------------------------------------------
1 | import { of } from 'rxjs';
2 | import { map } from 'rxjs/operators';
3 |
4 | //Identity law
5 | function identity(n){
6 | return n;
7 | }
8 |
9 | of(1, 2, 3)
10 | .pipe(
11 | map(identity)
12 | )
13 | .subscribe(console.log);
14 | //Observable 1,2,3
15 |
16 | //Composition law
17 | //observable.map(f).map(g) === observable.map(x => g(f(x)))
18 |
19 | function increment(n){
20 | return n + 1;
21 | }
22 |
23 | function double(n){
24 | return n * 2
25 | }
26 |
27 | of(1, 2, 3)
28 | .pipe(
29 | map(increment),
30 | map(double)
31 | )
32 | .subscribe(console.log);
33 | //Observable 4,6,8
34 |
35 | of(1, 2, 3)
36 | .pipe(
37 | map(x => double(increment(x)))
38 | )
39 | .subscribe(console.log);
40 | //Observable 4,6,8
--------------------------------------------------------------------------------
/CH 15 Observables/laws2.js:
--------------------------------------------------------------------------------
1 | import { of } from 'rxjs';
2 | import { mergeMap } from 'rxjs/operators';
3 |
4 | //Left identity
5 | //M(x).flatMap(f) === f(x)
6 |
7 | function f(n){
8 | return of(n + 1);
9 | }
10 |
11 | of(1)
12 | .pipe(
13 | mergeMap(f)
14 | )
15 | .subscribe(console.log);
16 | //Observable 2
17 |
18 | f(1)
19 | .subscribe(console.log);
20 | //Observable 2
21 |
22 | //Right identity
23 | //monad.flatMap(M) === monad
24 |
25 | function unit(value){
26 | return of(value)
27 | }
28 |
29 | of(1)
30 | .pipe(
31 | mergeMap(unit)
32 | )
33 | .subscribe(console.log);
34 | //Observable 1
35 |
36 | //Associativity
37 | //monad.flatMap(f).flatMap(g)
38 | // === monad.flatMap(x => f(x).flatMap(g)))
39 |
40 | function g(n){
41 | return of(n * 2);
42 | }
43 |
44 | of(1)
45 | .pipe(
46 | mergeMap(f),
47 | mergeMap(g)
48 | )
49 | .subscribe(console.log);
50 | //Observable 4
51 |
52 | of(1)
53 | .pipe(
54 | mergeMap( x => f(x).pipe(mergeMap(g)))
55 | )
56 | .subscribe(console.log);
57 | //Observable 4
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/CH 15 Observables/map.js:
--------------------------------------------------------------------------------
1 | import { of } from 'rxjs';
2 | import { map } from 'rxjs/operators';
3 |
4 | const dataSource = of(1, 2, 3);
5 |
6 | function double(n){
7 | return n * 2;
8 | }
9 |
10 | dataSource
11 | .pipe(
12 | map(double)
13 | )
14 | .subscribe(console.log);
--------------------------------------------------------------------------------
/CH 15 Observables/mergeAll.js:
--------------------------------------------------------------------------------
1 | import { from } from 'rxjs';
2 | import { ajax } from 'rxjs/ajax';
3 | import { map, mergeAll } from 'rxjs/operators';
4 |
5 | const observable = from([
6 | 'http://localhost:3000/dictionaries',
7 | 'http://localhost:3000/todos'
8 | ]);
9 |
10 | observable.pipe(
11 | map(ajax.getJSON),
12 | mergeAll()
13 | ).subscribe(console.log);
14 | //[{name: 'Dictionary'}]
15 | //[{title: 'To Do'}]
16 |
--------------------------------------------------------------------------------
/CH 15 Observables/mergeMap.js:
--------------------------------------------------------------------------------
1 | import { of, from } from 'rxjs';
2 | import { map, mergeMap, mergeAll } from 'rxjs/operators';
3 |
4 | function createGetNTerm(c){
5 | return function(n){
6 | return n * c + 1
7 | }
8 | }
9 |
10 | function toSequence(x) {
11 | const getNTerm = createGetNTerm(x);
12 | return of(1, 2, 3).pipe(
13 | map(getNTerm)
14 | )
15 | }
16 |
17 | toSequence(2)
18 | //.subscribe(console.log);
19 |
20 | toSequence(4)
21 | //.subscribe(console.log);
22 |
23 | // using map and mergeAll
24 | from([2, 4]).pipe(
25 | map(toSequence),
26 | mergeAll()
27 | )
28 | //.subscribe(console.log);
29 |
30 | // using mergeMap
31 | from([2, 4]).pipe(
32 | mergeMap(toSequence)
33 | )
34 | .subscribe(console.log);
--------------------------------------------------------------------------------
/CH 15 Observables/observers.js:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 |
3 | const observer = {
4 | next(value){
5 | console.log(`Next: ${value}`)
6 | },
7 | error(msg){
8 | console.error(`Error: ${msg}`)
9 | },
10 | complete(value){
11 | console.error(`Complete`)
12 | }
13 | };
14 |
15 | const observable = Observable.create(observer => {
16 | observer.next(1);
17 | observer.next(2);
18 | observer.complete('Done');
19 | });
20 | observable.subscribe(observer);
21 |
22 | const observable1 = Observable.create(observer => {
23 | observer.next(1);
24 | observer.next(2);
25 | observer.error('Failed');
26 | });
27 | observable1.subscribe(observer);
28 |
29 | observable.subscribe(value => console.log(`Next: ${value}`));
30 |
31 | observable.subscribe(
32 | value => console.log(`Next: ${value}`),
33 | msg => console.error(`Error: ${msg}`),
34 | () => console.error(`Complete`)
35 | );
--------------------------------------------------------------------------------
/CH 15 Observables/of.js:
--------------------------------------------------------------------------------
1 | import { of } from 'rxjs';
2 |
3 | const source = of(1, 2, 3, 4, 5);
4 | source
5 | .subscribe(console.log);
--------------------------------------------------------------------------------
/CH 15 Observables/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "observables",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@babel/core": "^7.10.2",
13 | "@babel/node": "^7.10.1",
14 | "@babel/preset-env": "^7.10.2",
15 | "rxjs": "^6.5.5"
16 | },
17 | "devDependencies": {
18 | "eslint": "^7.1.0",
19 | "eslint-plugin-functional": "^3.0.1"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/CH 15 Observables/pipe.js:
--------------------------------------------------------------------------------
1 | import { of } from 'rxjs';
2 | import { map, filter } from 'rxjs/operators';
3 |
4 | const dataSource = of(1, 2, 3, 4, 5);
5 |
6 | function isEven(n){
7 | return n % 2 === 0;
8 | }
9 |
10 | function double(n){
11 | return n * 2;
12 | }
13 |
14 | dataSource
15 | .pipe(
16 | filter(isEven),
17 | map(double)
18 | )
19 | .subscribe(console.log);
--------------------------------------------------------------------------------
/CH 15 Observables/run.bat:
--------------------------------------------------------------------------------
1 | npx babel-node create.js
--------------------------------------------------------------------------------
/CH 15 Observables/subscription.js:
--------------------------------------------------------------------------------
1 | import { interval } from 'rxjs';
2 |
3 | const observable = interval(1000);
4 | const subscription = observable.subscribe(console.log);
5 |
6 | // Later
7 | setTimeout(() => {
8 | subscription.unsubscribe();
9 | }, 3500);
10 |
--------------------------------------------------------------------------------
/CH 15 Observables/take.js:
--------------------------------------------------------------------------------
1 | import { of } from 'rxjs';
2 | import { take } from 'rxjs/operators';
3 |
4 | const source = of(1, 2, 3, 4, 5);
5 | source
6 | .pipe(
7 | take(3)
8 | )
9 | .subscribe(console.log);
--------------------------------------------------------------------------------
/CH 16 Elm Architecture/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | elm-stuff
--------------------------------------------------------------------------------
/CH 16 Elm Architecture/elm.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "application",
3 | "source-directories": [
4 | "src"
5 | ],
6 | "elm-version": "0.19.0",
7 | "dependencies": {
8 | "direct": {
9 | "elm/browser": "1.0.2",
10 | "elm/core": "1.0.5",
11 | "elm/html": "1.0.0",
12 | "elm/random": "1.0.0"
13 | },
14 | "indirect": {
15 | "elm/json": "1.1.3",
16 | "elm/time": "1.0.0",
17 | "elm/url": "1.0.0",
18 | "elm/virtual-dom": "1.0.2"
19 | }
20 | },
21 | "test-dependencies": {
22 | "direct": {},
23 | "indirect": {}
24 | }
25 | }
--------------------------------------------------------------------------------
/CH 16 Elm Architecture/run.bat:
--------------------------------------------------------------------------------
1 | elm make src/Counter.elm --output=dist/counter.html
--------------------------------------------------------------------------------
/CH 16 Elm Architecture/src/Counter.elm:
--------------------------------------------------------------------------------
1 | import Browser
2 | import Html exposing (Html, button, div, text)
3 | import Html.Events exposing (onClick)
4 |
5 | -- MODEL
6 |
7 | type alias Model = {
8 | number : Int
9 | }
10 |
11 | initialModel : Model
12 | initialModel = { number = 0 }
13 |
14 | -- MESSAGES
15 |
16 | type Msg = Increment | Decrement
17 |
18 | -- UPDATE
19 |
20 | update : Msg -> Model -> Model
21 | update msg model =
22 | case msg of
23 | Increment ->
24 | { model | number = model.number + 1 }
25 |
26 | Decrement ->
27 | { model | number = model.number - 1 }
28 |
29 | -- VIEW
30 |
31 | view : Model -> Html Msg
32 | view model =
33 | div []
34 | [
35 | div [] [ text (String.fromInt model.number) ]
36 | , button [ onClick Decrement ] [ text "-" ]
37 | , button [ onClick Increment ] [ text "+" ]
38 | ]
39 |
40 |
41 | main =
42 | Browser.sandbox { init = initialModel, update = update, view = view }
--------------------------------------------------------------------------------
/CH 16 Elm Architecture/src/RandomGenerator-update.js:
--------------------------------------------------------------------------------
1 | function update(model, action){
2 | switch(action.type){
3 | case 'GenerateNumber' : {
4 | const command = { name: 'Random.generate', resultMessage : 'SetNumber' };
5 | return [model, command];
6 | }
7 | case 'SetNumber' : {
8 | const newModel = { ...model, number: action.payload };
9 | const command = { name: 'Cmd.none' };
10 | return [newModel, command];
11 | }
12 | default : {
13 | const command = { name: 'Cmd.none' };
14 | return [model, command];
15 | }
16 | }
17 | }
18 |
19 | const [model, command] = update({}, 'GenerateNumber');
20 | console.log(model);
21 | console.log(command);
22 | //{}
23 | //{name: "Cmd.none"}
--------------------------------------------------------------------------------
/CH 16 Elm Architecture/src/RandomGenerator.elm:
--------------------------------------------------------------------------------
1 | import Browser
2 | import Html exposing (Html, button, div, text)
3 | import Html.Events exposing (onClick)
4 | import Random
5 |
6 | -- MODEL
7 |
8 | type alias Model = {
9 | number : Int
10 | }
11 |
12 |
13 | initModel : () -> (Model, Cmd Msg)
14 | initModel _ =
15 | ( Model 0
16 | , Cmd.none
17 | )
18 |
19 | -- MESSAGES & COMMANDS
20 |
21 | type Msg = GenerateNumber | SetNumber Int
22 |
23 | -- UPDATE
24 |
25 | update : Msg -> Model -> (Model, Cmd Msg)
26 | update msg model =
27 | case msg of
28 | GenerateNumber ->
29 | ( model
30 | , Random.generate SetNumber (Random.int 1 100)
31 | )
32 |
33 | SetNumber number ->
34 | ( Model number
35 | , Cmd.none
36 | )
37 |
38 | -- VIEW
39 |
40 | view : Model -> Html Msg
41 | view model =
42 | div []
43 | [
44 | div [] [ text (String.fromInt model.number) ]
45 | , button [ onClick GenerateNumber ] [ text "Generate" ]
46 | ]
47 |
48 |
49 | -- SUBSCRIPTIONS
50 |
51 |
52 | subscriptions : Model -> Sub Msg
53 | subscriptions model =
54 | Sub.none
55 |
56 | main =
57 | Browser.element { init = initModel, update = update, view = view, subscriptions = subscriptions }
--------------------------------------------------------------------------------
/CH 16 Redux Commands/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["react-app"],
3 | "plugins": [
4 | "immutable"
5 | ],
6 | "rules": {
7 | "immutable/no-this": "error",
8 | "immutable/no-mutation": "error"
9 | }
10 | }
--------------------------------------------------------------------------------
/CH 16 Redux Commands/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/CH 16 Redux Commands/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `npm start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `npm test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `npm run build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `npm run eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `npm run build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/CH 16 Redux Commands/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "my-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.5.0",
8 | "@testing-library/user-event": "^7.2.1",
9 | "react": "^16.13.1",
10 | "react-dom": "^16.13.1",
11 | "react-redux": "^7.2.0",
12 | "react-scripts": "3.4.1",
13 | "redux": "^4.0.5",
14 | "redux-thunk": "^2.3.0"
15 | },
16 | "scripts": {
17 | "start": "npx eslint src && react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test",
20 | "eject": "react-scripts eject"
21 | },
22 | "eslintConfig": {
23 | "extends": "react-app"
24 | },
25 | "browserslist": {
26 | "production": [
27 | ">0.2%",
28 | "not dead",
29 | "not op_mini all"
30 | ],
31 | "development": [
32 | "last 1 chrome version",
33 | "last 1 firefox version",
34 | "last 1 safari version"
35 | ]
36 | },
37 | "devDependencies": {
38 | "eslint-plugin-immutable": "^1.0.0"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/CH 16 Redux Commands/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 | You need to enable JavaScript to run this app.
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/CH 16 Redux Commands/src/Counter.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { GenerateNumber } from './store';
4 |
5 | function Counter({number, GenerateNumber}){
6 | return(
7 |
8 |
{number}
9 |
Generate
12 |
13 | )
14 | }
15 |
16 | export default connect(
17 | state => state,
18 | { GenerateNumber }
19 | )(Counter)
--------------------------------------------------------------------------------
/CH 16 Redux Commands/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { Provider } from 'react-redux';
4 | import { createStore, applyMiddleware } from 'redux';
5 | import thunk from 'redux-thunk';
6 | import { reducer } from './store';
7 | import Counter from "./Counter";
8 |
9 | const store = createStore(reducer, applyMiddleware(thunk));
10 |
11 | ReactDOM.render(
12 |
13 |
14 |
15 |
16 | ,
17 | document.getElementById('root')
18 | );
19 |
--------------------------------------------------------------------------------
/CH 16 Redux Commands/src/store.js:
--------------------------------------------------------------------------------
1 | //MODEL
2 | const initialModel = {
3 | number: 0
4 | };
5 |
6 | //COMMANDS
7 | function GenerateNumber(){
8 | return function(dispatch){
9 | const number = Math.floor(Math.random() * 100);
10 | dispatch(SetNumber(number));
11 | }
12 | }
13 |
14 | //MESSAGES
15 | function SetNumber(number){
16 | return {
17 | type : SetNumber.name,
18 | number
19 | }
20 | }
21 |
22 | //UPDATE
23 | function reducer(model = initialModel, action){
24 | switch(action.type){
25 | case SetNumber.name:
26 | return { ...model, number: action.number };
27 | default:
28 | return model;
29 | }
30 | }
31 |
32 | export { reducer, GenerateNumber };
--------------------------------------------------------------------------------
/CH 16 Redux/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["react-app"],
3 | "plugins": [
4 | "immutable"
5 | ],
6 | "rules": {
7 | "immutable/no-this": "error",
8 | "immutable/no-mutation": "error"
9 | }
10 | }
--------------------------------------------------------------------------------
/CH 16 Redux/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/CH 16 Redux/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `npm start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `npm test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `npm run build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `npm run eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `npm run build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/CH 16 Redux/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "my-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.5.0",
8 | "@testing-library/user-event": "^7.2.1",
9 | "react": "^16.13.1",
10 | "react-dom": "^16.13.1",
11 | "react-redux": "^7.2.0",
12 | "react-scripts": "3.4.1",
13 | "redux": "^4.0.5"
14 | },
15 | "scripts": {
16 | "start": "npx eslint src && react-scripts start",
17 | "build": "react-scripts build",
18 | "test": "react-scripts test",
19 | "eject": "react-scripts eject"
20 | },
21 | "eslintConfig": {
22 | "extends": "react-app"
23 | },
24 | "browserslist": {
25 | "production": [
26 | ">0.2%",
27 | "not dead",
28 | "not op_mini all"
29 | ],
30 | "development": [
31 | "last 1 chrome version",
32 | "last 1 firefox version",
33 | "last 1 safari version"
34 | ]
35 | },
36 | "devDependencies": {
37 | "eslint-plugin-immutable": "^1.0.0"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/CH 16 Redux/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 | You need to enable JavaScript to run this app.
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/CH 16 Redux/src/Counter.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { Increment, Decrement } from './store';
4 |
5 | function Counter({number, Increment, Decrement}){
6 | return(
7 |
8 |
{number}
9 |
-
12 |
+
15 |
16 | )
17 | }
18 |
19 | export default connect(
20 | state => state,
21 | {Increment, Decrement}
22 | )(Counter);
--------------------------------------------------------------------------------
/CH 16 Redux/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { createStore } from 'redux';
4 | import { Provider } from 'react-redux';
5 | import Counter from './Counter';
6 | import { reducer } from './store';
7 |
8 | const store = createStore(reducer);
9 |
10 | ReactDOM.render(
11 |
12 |
13 |
14 |
15 | ,
16 | document.getElementById('root')
17 | );
18 |
--------------------------------------------------------------------------------
/CH 16 Redux/src/store.js:
--------------------------------------------------------------------------------
1 | //MODEL
2 | const initialModel = {
3 | number: 0
4 | };
5 |
6 | //MESSAGES
7 | function Increment(){
8 | return {
9 | type : Increment.name
10 | }
11 | }
12 |
13 | function Decrement(){
14 | return {
15 | type : Decrement.name
16 | }
17 | }
18 |
19 | //UPDATE
20 | function reducer(model = initialModel, action){
21 | switch(action.type){
22 | case Increment.name:
23 | return { ...model, number: model.number + 1 };
24 | case Decrement.name:
25 | return { ...model, number: model.number - 1 };
26 | default:
27 | return model;
28 | }
29 | }
30 |
31 | export { reducer, Increment, Decrement };
--------------------------------------------------------------------------------
/CH 17 Redux Axios/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["react-app"],
3 | "plugins": [
4 | "immutable"
5 | ],
6 | "rules": {
7 | "immutable/no-this": "error",
8 | "immutable/no-mutation": "error"
9 | }
10 | }
--------------------------------------------------------------------------------
/CH 17 Redux Axios/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/CH 17 Redux Axios/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `npm start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `npm test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `npm run build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `npm run eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `npm run build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/CH 17 Redux Axios/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "my-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.5.0",
8 | "@testing-library/user-event": "^7.2.1",
9 | "axios": "^0.19.2",
10 | "react": "^16.13.1",
11 | "react-dom": "^16.13.1",
12 | "react-redux": "^7.2.0",
13 | "react-scripts": "3.4.1",
14 | "redux": "^4.0.5",
15 | "redux-axios-middleware": "^4.0.1"
16 | },
17 | "scripts": {
18 | "start": "npx eslint src && react-scripts start",
19 | "build": "react-scripts build",
20 | "test": "react-scripts test",
21 | "eject": "react-scripts eject"
22 | },
23 | "eslintConfig": {
24 | "extends": "react-app"
25 | },
26 | "browserslist": {
27 | "production": [
28 | ">0.2%",
29 | "not dead",
30 | "not op_mini all"
31 | ],
32 | "development": [
33 | "last 1 chrome version",
34 | "last 1 firefox version",
35 | "last 1 safari version"
36 | ]
37 | },
38 | "devDependencies": {
39 | "eslint-plugin-immutable": "^1.0.0",
40 | "redux-devtools-extension": "^2.13.8"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/CH 17 Redux Axios/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 | You need to enable JavaScript to run this app.
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/CH 17 Redux Axios/src/List.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { LoadTodos } from './store';
4 |
5 | function List({todos, LoadTodos}){
6 | return(
7 |
8 |
9 |
12 | Refresh
13 |
14 |
15 |
16 | { todos.map(todo =>
17 | {todo.title} )}
18 |
19 |
20 | )
21 | }
22 |
23 | export default connect(
24 | state => state,
25 | { LoadTodos }
26 | )(List)
--------------------------------------------------------------------------------
/CH 17 Redux Axios/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { Provider } from 'react-redux';
4 | import { createStore, applyMiddleware } from 'redux';
5 | import axios from 'axios';
6 | import axiosMiddleware from 'redux-axios-middleware';
7 | import { composeWithDevTools } from 'redux-devtools-extension';
8 | import { reducer } from './store';
9 | import List from "./List";
10 |
11 | const client = axios.create({
12 | baseURL:'http://localhost:3000/',
13 | responseType: 'json'
14 | });
15 |
16 | const store = createStore(reducer, composeWithDevTools(
17 | applyMiddleware(
18 | axiosMiddleware(client)
19 | )
20 | ));
21 |
22 | ReactDOM.render(
23 |
24 |
25 |
26 |
27 | ,
28 | document.getElementById('root')
29 | );
--------------------------------------------------------------------------------
/CH 17 Redux Axios/src/store.js:
--------------------------------------------------------------------------------
1 | //MODEL
2 | const initialModel = {
3 | todos: []
4 | };
5 |
6 | //MESSAGES
7 | function LoadTodos(){
8 | return {
9 | type: LoadTodos.name,
10 | payload: {
11 | request:{
12 | url:'/todos'
13 | }
14 | }
15 | }
16 | }
17 |
18 | //UPDATE
19 | function reducer(model = initialModel, action){
20 | switch(action.type){
21 | case `${LoadTodos.name}_SUCCESS`:
22 | return {
23 | ...model,
24 | todos: action.payload.data
25 | };
26 | default:
27 | return model;
28 | }
29 | }
30 |
31 | export { reducer, LoadTodos };
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | ### Functional Programming in JavaScript
2 | #### Source Code
3 |
4 | In this book, you will find how to use JavaScript as a functional programming language.
5 |
6 | It turns out that JavaScript has everything it needs to be used as a functional language. We just have to remove features from the language starting with the 'this' keyword.
7 |
8 | Functions are values. Functions can operate on other functions.
9 | Inner functions can access variables from the outer functions even after the outer functions have executed.
10 |
11 | Functional programming makes code easier to read, understand, test, and debug.
12 |
13 | * Here are some of the things you will learn:
14 |
15 | * How to disable 'this' and enable immutable data objects using a linter
16 |
17 | * How to work with immutable objects and collections
18 |
19 | * How to do data transformations using core operations like filter, map, sort, or reduce
20 |
21 | * How to use statements like if and switch in a functional way
22 |
23 | * How to create pipelines and use currying to pass additional data
24 |
25 | * How to create and use functors and monads
26 |
27 | * How to work with promises and observables
28 |
29 | * Understand the Elm Architecture
30 |
31 | [https://www.amazon.com/dp/B08CZZ4FQQ](https://www.amazon.com/dp/B08CZZ4FQQ)
32 |
33 | [https://www.amazon.co.uk/dp/B08CZZ4FQQ](https://www.amazon.co.uk/dp/B08CZZ4FQQ)
34 |
35 | [https://www.amazon.es/dp/B08CZZ4FQQ](https://www.amazon.de/dp/B08CZZ4FQQ)
36 |
37 | [https://www.amazon.fr/dp/B08CZZ4FQQ](https://www.amazon.de/dp/B08CZZ4FQQ)
--------------------------------------------------------------------------------