This commit is contained in:
Michael Zhang 2023-04-14 15:36:03 -05:00
commit 09877676bb
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
25 changed files with 5297 additions and 0 deletions

3
.eslintrc.json Normal file
View file

@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}

35
.gitignore vendored Normal file
View file

@ -0,0 +1,35 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

38
README.md Normal file
View file

@ -0,0 +1,38 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

View file

@ -0,0 +1,21 @@
import useSWR from "swr";
import ReactMarkdown from "react-markdown";
const fetcher = (...args) => fetch(...args).then((res) => res.json());
const LessonContainer = ({ name }) => {
const { data, error, isLoading } = useSWR(
`/api/lesson?name=${name}`,
fetcher
);
return (
<>
<h1>Lesson about {name}</h1>
{!isLoading && !error && <ReactMarkdown>{data.contents}</ReactMarkdown>}
</>
);
};
export default LessonContainer;

3
lessons/expressions.md Normal file
View file

@ -0,0 +1,3 @@
# Expressions
## Pattern Matching

90
lessons/functions.md Normal file
View file

@ -0,0 +1,90 @@
# Functions
As you might've guessed, the foundations of functional programming are
_functions_! Yes, exactly in the math sense. If high school math is getting a
bit hazy for you, here's a recap:
- Functions take a single input (or multiple inputs, but we'll get into this a
bit later!) and produce a single output
- f(1) = 2
- f(2) = 4
- f(3) = 6
- Multiple inputs are allowed to produce a single output
- g(1) = 1
- g(2) = 1
- g(3) = 2
- A single output cannot produce two different values!
- h(1) = 1
- h(2) = 2
This isn't a function. Think of functions as being this unchangeable binding
between one input and a certain output. If you evaluate the function again, it
should always produce that same output, so it doesn't make sense for a
function to simultaneously give two outputs for a single input. This property
is called function _purity_.
> There are also impure functions, which have _side effects_. For now, we will
> focus on pure functions.
> Example questions:
>
> - Which of the following are functions? (give a few functions)
## Functions can call other functions
The output of a function is really just like any other expression that you could
write. For example:
- 1, 5+5, log(x) is a valid output. f(x) = 1, g(x) = 5+5, h(x) = log(x)
- Any expression involving the input is valid. f(x) = 2 \* x
- Calling the function again is valid! f(x) = f(x - 1)
- _There are a few restrictions to this. We'll see how this works later_
In general, we can say that function calls are part of what we consider
expressions. Since the right side of functions are also expressions, we can call
functions inside functions!
- See also: Expressions
## Functions are first class
In traditional arithmetic, we think of functions as rather _privileged_.
Functions are these operations that we can _do_ to numbers, which are different
from numbers.
Well, not anymore. Functions themselves are also expressions now! We can talk
about passing them around to other functions, but not much in the realm of
arithmetic.
- Venn diagram:
- Functions
- Can be called
- Both
- Can be passed around as variables
- Numbers
- Can be added / subtracted / multiplied / divided
- Can take square roots and compute lots of functions
If you noticed, all we really added was this middle part. But this gives us a
lot of power to use functions. Say you wanted to write a function called
**repeat**. All it does is repeat a function several times. For example,
- If I have f(x) = 2x, then repeat(f, 5) = f(f(f(f(f(x))))) = 32x
- If I have g(x) = 3x - 1, then repeat(g, 2) = 3(3x - 1) - 1 = 9x - 4
In this case, the function **repeat** is known as a _higher order function_. It
takes a function as its parameter, and can freely call it or pass it around.
There are a few very useful and popular higher order functions:
- map
- filter
- fold
## Recursion
## Currying

3
lessons/other-topics.md Normal file
View file

@ -0,0 +1,3 @@
# Other Topics
## Closures

3
lessons/state.md Normal file
View file

@ -0,0 +1,3 @@
# State
## Monads

5
lessons/streams.md Normal file
View file

@ -0,0 +1,5 @@
# Streams
## Laziness
## Iterators

17
lessons/types.md Normal file
View file

@ -0,0 +1,17 @@
# Types
## Strict Types
## Primitive Types
## Type Constructors
### Option
## Recursive Data Types
### Lists
### Trees
## Abstraction

6
next.config.js Normal file
View file

@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
}
module.exports = nextConfig

4869
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

29
package.json Normal file
View file

@ -0,0 +1,29 @@
{
"name": "fpcourse",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@types/node": "18.15.11",
"@types/react": "18.0.35",
"@types/react-dom": "18.0.11",
"autoprefixer": "10.4.14",
"eslint": "8.38.0",
"eslint-config-next": "13.3.0",
"next": "13.3.0",
"postcss": "8.4.21",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-markdown": "^8.0.7",
"tailwindcss": "3.3.1",
"typescript": "5.0.4"
},
"devDependencies": {
"swr": "^2.1.3"
}
}

6
pages/_app.tsx Normal file
View file

@ -0,0 +1,6 @@
import '@/styles/globals.css'
import type { AppProps } from 'next/app'
export default function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}

13
pages/_document.tsx Normal file
View file

@ -0,0 +1,13 @@
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}

13
pages/api/hello.ts Normal file
View file

@ -0,0 +1,13 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next'
type Data = {
name: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
res.status(200).json({ name: 'John Doe' })
}

15
pages/api/lesson.ts Normal file
View file

@ -0,0 +1,15 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import { readFile } from "fs/promises";
import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { name } = req.query;
const result = await readFile(`lessons/${name}.md`);
const resultString = result.toString();
res.status(200).json({ contents: resultString });
}

59
pages/index.tsx Normal file
View file

@ -0,0 +1,59 @@
import dynamic from "next/dynamic";
import { Inter } from "next/font/google";
import { useState } from "react";
export default function Home() {
const [showBanner, setShowBanner] = useState(true);
const [lessons, setLessons] = useState<Element[]>([]);
const loadLesson = (name: string) => {
setShowBanner(false);
const LessonContainer = dynamic(
() => import("../components/LessonContainer"),
{ loading: () => <p>Loading...</p> }
);
setLessons([...lessons, <LessonContainer name={name} />]);
};
return (
<main>
<details
className="intro"
open={showBanner}
>
<summary>Intro</summary>
<p>
Functional programming is a structured way of thinking that gives us a
better understanding about how programs behave. Although it relies on
theoretical foundations, the things you will take away will help guide
your thinking no matter what paradigm!
</p>
<p>
Ready to start learning functional programming? Click one of the
buttons below to get started!
</p>
<button onClick={() => loadLesson("functions")}>
Get Started
<br />
<small>Functions &darr;</small>
</button>
<button onClick={() => loadLesson("types")}>
Get Started
<br />
<small>Types &darr;</small>
</button>
<button onClick={() => loadLesson("state")}>
Get Started
<br />
<small>State &darr;</small>
</button>
</details>
{lessons}
</main>
);
}

6
postcss.config.js Normal file
View file

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

1
public/next.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

1
public/vercel.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>

After

Width:  |  Height:  |  Size: 629 B

20
styles/globals.css Normal file
View file

@ -0,0 +1,20 @@
body, html {
margin: 0;
padding: 0;
}
main {
width: 890px;
margin: auto;
font-family: sans-serif;
}
.intro {
background: white;
position: sticky;
top: 0;
z-index: 20p;
padding: 20px;
border-bottom: 1px solid lightgray;
}

18
tailwind.config.js Normal file
View file

@ -0,0 +1,18 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
'./app/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {
backgroundImage: {
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
'gradient-conic':
'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
},
},
},
plugins: [],
}

23
tsconfig.json Normal file
View file

@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}