DAY 11
0
Software Development

yo, what's up?

## Product Type

Product types 允許同時存在兩種以上的資料型態在內

``````class Clock {
constructor(hour, period) {
if(!Array.from({length: 12}, (_, i) => i + 1).includes(hour) || !['AM', 'PM'].includes(period)){
throw new Error('format error!')
}
this.hour = hour;
this.period = period;
}
}
``````

``````const One_AM = new Clock(1, "AM");
const Two_AM = new Clock(2, "AM");

// ... 以此類推
``````

``````C([A, B]) = C(A) * C(B)
``````

C(A): 為 type `A` 有多少種元素在內。例如 `Hour` 有 12 種。

## Sum Type

Sum types 則每次只能有一組固定的資料型態

``````C(A | B) = C(A) + C(B)
``````

``````const CREATE_TODO = 'CREATE_TODO'
const REMOVE_TODO = 'REMOVE_TODO'

{
type: CREATE_TODO,
text
}

{
type: REMOVE_TODO,
id,
}
``````

``````const create = (text) => ({
type: CREATE_TODO,
text
})

const remove = (id) => ({
type: REMOVE_TODO,
id
})
``````

``````type LinkedList<A> =
| { readonly _tag: 'Nil' }
``````

`LinkedList<A>` 就是 recursion.

### Pattern matching

``````const nil = { _tag: 'Nil' };

const cons = (head, tail) => ({
_tag: 'Cons',
tail,
});

const match = (onNil, onCons) => (fa) => {
switch (fa._tag) {
case 'Nil':
return onNil();
case 'Cons':
}
};

// 此 LinkedList 是否為空
const isEmpty = match(
() => true,
() => false
);

// 新增 item 在 LinkedList 中
const addFirst = (num) =>
match(
() => cons(num, nil),
);

// 取得該 LinkedList 第一個數值
const head = match(
() => undefined,
);

// 取得該 LinkedList 最後一個數值
const last = match(
() => undefined,
(head, tail) => (tail._tag === 'Nil' ? head : last(tail))
);

// 取得該 LinkedList 長度
const length = match(
() => 0,
(_, tail) => 1 + length(tail)
);

const myList = cons(1, cons(2, cons(3, nil)));

isEmpty(myList) // false
``````

### Sum Type in UI Display

``````import React, { useState, useEffect } from 'react';

const App = () => {
const [error, setError] = useState(null);
const [data, setData] = useState(null);

...

return <>{!loading && !error && data.map(/** rendering */)}</>
}
``````

``````const match = (onInit, onLoading, onError, onSuccess) => (fa) => {
switch (fa._tag) {
case 'INIT':
return onInit();
case 'ERROR':
return onError(fa.error);
case 'SUCCESS':
return onSuccess(fa.data);
default:
break;
}
};

const STATE = {
INIT: { _tag: 'INIT' },
ERROR: (error) => ({
_tag: 'ERROR',
error,
}),
SUCCESS: (data) => ({ _tag: 'SUCCESS', data }),
};
``````

``````import React, { useEffect, useState } from 'react';

export default function App() {
const [result, setResult] = useState(STATE.INIT);

useEffect(() => {
const runEffect = () => {

fetch('https://jsonplaceholder.typicode.com/todos')
.then((response) => response.json())
.then((data) => setResult(STATE.SUCCESS(data)))
.catch((error) => setResult(STATE.ERROR(error)))
};

runEffect();
}, []);

const renderer = match(
() => <div>initial...</div>,
(error) => <div>{JSON.stringify(error)}</div>,
(xs) =>
xs.map((x) => (
<code key={x.id}>
<pre>{JSON.stringify(x, null, 2)}</pre>
</code>
))
);

return <>{renderer(result)}</>;
}
``````

avaliable on stackblitz

## 小結

Product Type 適合用在兩值相互獨立的情況， Sum Type 則適合用在兩值相依的情況，而 ADT 的概念的應用在處理業務邏輯上。

NEXT: Semigroup

## Reference

### 1 則留言

1
Ken Chen
iT邦新手 5 級 ‧ 2021-10-01 22:24:09