Skip to content

Commit 07f3de4

Browse files
committed
Fix approach for arithmetics and refactors factorial/fibo implementation
1 parent a1f52af commit 07f3de4

File tree

5 files changed

+93
-160
lines changed

5 files changed

+93
-160
lines changed

src/App.css

-42
This file was deleted.

src/App.tsx

+34-33
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,81 @@
1-
import { FC, useContext, useEffect, useRef, useState } from "react";
2-
import { CallElement, CallFunction, Return, IfElse } from "./program/compute";
3-
import { Add, Multiply, One, Two, multiplyNodes, nodeToNumber, numberToNode } from "./program/natural-numbers";
1+
import React, { FC, useEffect, useRef, useState } from 'react';
2+
import { CallElement, CallFunction, IfElse, EvaluateAll } from './program/compute';
3+
import { Add, Multiply, N, One, numberToNode } from './program/natural-numbers';
44

5-
const Factorial: FC<any> = ({ n }) => {
6-
const onReturn = useContext(Return);
7-
const [count, setCount] = useState(n); // TODO: Subtraction
5+
const Factorial: FC<any> = React.memo(({ n }) => {
6+
const [count, setCount] = useState(n);
87
const [result, setResult] = useState(<One />);
98

109
useEffect(() => {
11-
setCount(count - 1);
12-
setResult((result) => <>{multiplyNodes(numberToNode(count), result)}</>);
10+
if ((window as any).PLEASE_STOP) return;
11+
// TODO: Subtraction in react
12+
// TODO: Fix timeout
13+
setTimeout(() => setCount(count - 1), 50)
1314
}, [count]);
1415

1516
return (
1617
<>
1718
Calculating factorial of {n}...
1819
<IfElse condition={count <= 1}>
19-
<CallElement fn={<Add>{result}</Add>}>
20-
{result => <CallFunction fn={() => onReturn(result)} />}
20+
<Add>{result}</Add>
21+
<CallElement key={count} fn={<Multiply a={result} b={numberToNode(count)} />}>
22+
{product => <CallFunction fn={() => setResult(numberToNode(product))} />}
2123
</CallElement>
22-
<></>
2324
</IfElse>
2425
</>
2526
);
26-
};
27+
});
2728

28-
const Fibonacci: FC<any> = ({ n }) => {
29-
const onReturn = useContext(Return);
29+
const Fibonacci: FC<any> = React.memo(({ n }) => {
3030
const [count, setCount] = useState(n);
3131
const prevResult = useRef(<></>);
3232
const [result, setResult] = useState(<One />);
3333

3434
useEffect(() => {
35-
setCount(count - 1);
36-
const prev = prevResult.current;
37-
prevResult.current = result;
38-
setResult((result) => <>{result}{prev}</>);
35+
if ((window as any).PLEASE_STOP) return;
36+
setTimeout(() => setCount(count - 1), 50);
3937
}, [count, result]);
4038

4139
return (
4240
<>
4341
Calculating fibonacci number {n}...
44-
<IfElse condition={count <= 1}>
45-
<CallElement fn={<Add>{result}</Add>}>
46-
{result => <CallFunction fn={() => onReturn(result)} />}
42+
<IfElse condition={count < 1}>
43+
<Add>{result}</Add>
44+
<CallElement key={count} fn={<Add>{prevResult.current}{result}</Add>}>
45+
{sum => <CallFunction fn={() => {
46+
prevResult.current = result;
47+
setResult(numberToNode(sum));
48+
}} />}
4749
</CallElement>
48-
<></>
4950
</IfElse>
5051
</>
5152
);
52-
};
53+
});
5354

5455
const App: FC = () => {
5556
return (
56-
<>
57+
<div>
5758
<div>
58-
<CallElement fn={<Multiply a={<><Two /><One /></>} b={<Two />} />}>
59-
{(result) => <>3 * 2 = {result}</>}
59+
<CallElement fn={<Add> <N._5 /> <N._3 /> <N._4 /> </Add>}>
60+
{(result) => <>5 + 3 + 4 = {result}</>}
6061
</CallElement>
6162
</div>
6263
<div>
63-
<CallElement fn={<Add> <One /> <Two /> <Two /> </Add>}>
64-
{(result) => <>1 + 2 + 2 = {result}</>}
64+
<CallElement fn={<Multiply a={<><N._3 /><N._5 /></>} b={<N._3 />} />}>
65+
{(result) => <>8 * 3 = {result}</>}
6566
</CallElement>
6667
</div>
6768
<div>
68-
<CallElement fn={<Factorial n={10} />}>
69-
{(result) => <>Facto: {result}</>}
69+
<CallElement fn={<Factorial n={5} />}>
70+
{(result) => <>Factorial(5): {result}</>}
7071
</CallElement>
7172
</div>
7273
<div>
73-
<CallElement fn={<Fibonacci n={8} />}>
74-
{(result) => <>Fibo: {result}</>}
74+
<CallElement fn={<EvaluateAll fns={Array.from({ length: 10 }, (_, i) => <Fibonacci n={i} key={i} />)} />}>
75+
{(result) => <>Fibo: {result.join(', ')}</>}
7576
</CallElement>
7677
</div>
77-
</>
78+
</div>
7879
);
7980
};
8081

src/index.css

+10-64
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,14 @@
1-
:root {
2-
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
3-
line-height: 1.5;
4-
font-weight: 400;
5-
6-
color-scheme: light dark;
7-
color: rgba(255, 255, 255, 0.87);
8-
background-color: #242424;
9-
10-
font-synthesis: none;
11-
text-rendering: optimizeLegibility;
12-
-webkit-font-smoothing: antialiased;
13-
-moz-osx-font-smoothing: grayscale;
14-
}
15-
16-
a {
17-
font-weight: 500;
18-
color: #646cff;
19-
text-decoration: inherit;
20-
}
21-
a:hover {
22-
color: #535bf2;
23-
}
24-
25-
body {
1+
html, body {
262
margin: 0;
27-
display: flex;
28-
place-items: center;
29-
min-width: 320px;
30-
min-height: 100vh;
3+
padding: 0;
4+
font: unset;
5+
background-color: #f0f0f0;
316
}
327

33-
h1 {
34-
font-size: 3.2em;
35-
line-height: 1.1;
36-
}
37-
38-
button {
39-
border-radius: 8px;
40-
border: 1px solid transparent;
41-
padding: 0.6em 1.2em;
42-
font-size: 1em;
43-
font-weight: 500;
44-
font-family: inherit;
45-
background-color: #1a1a1a;
46-
cursor: pointer;
47-
transition: border-color 0.25s;
48-
}
49-
button:hover {
50-
border-color: #646cff;
51-
}
52-
button:focus,
53-
button:focus-visible {
54-
outline: 4px auto -webkit-focus-ring-color;
55-
}
56-
57-
@media (prefers-color-scheme: light) {
58-
:root {
59-
color: #213547;
60-
background-color: #ffffff;
61-
}
62-
a:hover {
63-
color: #747bff;
64-
}
65-
button {
66-
background-color: #f9f9f9;
67-
}
8+
body {
9+
font-size: 1.6em;
10+
padding: 1rem;
11+
margin: 2rem auto;
12+
max-width: 800px;
13+
letter-spacing: 0.1rem;
6814
}

src/program/compute.tsx

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { FC, useEffect, Suspense, use, useMemo, useRef, ReactNode, Children, useReducer, useCallback } from 'react'
1+
import React, { FC, useEffect, Suspense, use, useMemo, useRef, ReactNode, Children, useReducer, useCallback, useContext } from 'react'
22

33
declare module 'react' {
44
export function use<T>(x: Promise<T>): T | undefined;
@@ -45,3 +45,28 @@ export const CallElement: FC<{
4545
</Suspense>
4646
)
4747
}
48+
49+
export const EvaluateAll: FC<{ fns: ReactNode[] }> = ({ fns }) => {
50+
const onReturn = useContext(Return);
51+
const resultList = useRef<any[]>([]);
52+
const resultCount = useRef(0);
53+
54+
const resolve = useCallback((result: any, i: number) => {
55+
resultList.current[i] = result;
56+
resultCount.current += 1;
57+
if (resultCount.current === fns.length) {
58+
onReturn(resultList.current);
59+
}
60+
}, [fns.length, onReturn])
61+
62+
return (
63+
<>
64+
{fns.map((fn, i) => (
65+
<CallElement key={i} fn={fn}>
66+
{result => <CallFunction fn={() => resolve(result, i)} />}
67+
</CallElement>
68+
))}
69+
</>
70+
)
71+
}
72+

src/program/natural-numbers.tsx

+23-20
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,38 @@
1-
import React, { FC, ReactNode, useContext, useEffect } from "react";
2-
import { Return } from "./compute";
3-
import TestRenderer from 'react-test-renderer'
4-
5-
export const One: FC = () => <div data-type="nat" />;
6-
export const Two: FC = () => <><One /><One /></>;
7-
8-
export const nodeToNumber = (node: ReactNode) => {
9-
const renderer = TestRenderer.create(<>{node}</>);
10-
const ones = renderer.root?.findAllByType(One);
11-
return ones.length ?? 0;
1+
import { FC, Fragment, ReactNode, useContext, useEffect, useRef } from 'react';
2+
import { CallElement, Return } from './compute';
3+
4+
export const One = () => <div data-type="nat" />;
5+
6+
export const N = {
7+
_0: () => <></>,
8+
_1: () => <One />,
9+
_2: () => <><One /><One /></>,
10+
_3: () => <><One /><One /><One /></>,
11+
_4: () => <><One /><One /><One /><One /></>,
12+
_5: () => <><One /><One /><One /><One /><One /></>,
1213
}
1314

1415
export const numberToNode = (n: number) => {
1516
const ones = Array.from({ length: n }, (_, i) => <One key={i} />);
1617
return <>{ones}</>;
1718
}
1819

19-
export const multiplyNodes = (a: ReactNode, b: ReactNode) => {
20-
const renderer = TestRenderer.create(<>{b}</>);
21-
return renderer.root?.findAllByType(One).map(_ => React.cloneElement(a as any));
22-
}
23-
2420
export const Add: FC<{ children?: ReactNode }> = ({ children }) => {
2521
const onReturn = useContext(Return);
22+
const ref = useRef<HTMLElement | null>(null);
2623

2724
useEffect(() => {
28-
onReturn(nodeToNumber(children));
25+
const count = Array.from(ref.current?.querySelectorAll('[data-type="nat"]') ?? []).length;
26+
onReturn(count);
2927
}, [children, onReturn]);
3028

31-
return null;
29+
return <div ref={ref as any}>{children}</div>;
3230
}
3331

34-
export const Multiply: FC<{ a: ReactNode, b: ReactNode }> = ({ a, b }) =>
35-
<Add>{multiplyNodes(a, b)}</Add>;
32+
export const Multiply: FC<{ a: ReactNode, b: ReactNode }> = ({ a, b }) => {
33+
return <CallElement fn={<Add>{a}</Add>}>
34+
{aNum => <Add>{Array.from({ length: aNum }, (_, i) => (
35+
<Fragment key={i}>{b}</Fragment>
36+
))}</Add>}
37+
</CallElement>
38+
};

0 commit comments

Comments
 (0)