[{"data":1,"prerenderedAt":2805},["ShallowReactive",2],{"page-\u002Fjs\u002F23-functional-programming":3},{"id":4,"title":5,"body":6,"description":2798,"extension":2799,"meta":2800,"navigation":70,"path":2801,"seo":2802,"stem":2803,"__hash__":2804},"content\u002Fjs\u002F23-functional-programming.md","JavaScript 23 — Functional Programming: Immutability, Pure Functions & Monads",{"type":7,"value":8,"toc":2789},"minimark",[9,14,19,446,450,823,827,1401,1405,1849,1853,2428,2432,2588,2592,2596,2638,2785],[10,11,13],"h1",{"id":12},"_23-functional-programming-immutability-pure-functions-monads","23 — Functional Programming: Immutability, Pure Functions & Monads",[15,16,18],"h2",{"id":17},"pure-functions-and-referential-transparency","Pure Functions and Referential Transparency",[20,21,23],"code-wrapper",{"language":22},"javascript",[24,25,29],"pre",{"className":26,"code":27,"language":22,"meta":28,"style":28},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F ── A pure function: same input → same output, no side effects ──\n\u002F\u002F Pure functions are:\n\u002F\u002F   - Deterministic (same input → same output, always)\n\u002F\u002F   - Side-effect-free (no mutation of external state, no I\u002FO, no randomness)\n\u002F\u002F   - Referentially transparent (can replace the call with its result)\n\n\u002F\u002F ✅ Pure function (deterministic, no side effects)\nconst add = (a, b) => a + b;\nadd(1, 2);  \u002F\u002F always 3 — can replace with `3` anywhere (referential transparency)\n\n\u002F\u002F ✅ Pure: no external state, no mutation\nconst greet = (name) => `Hello, ${name}!`;\ngreet(\"Alice\");  \u002F\u002F always \"Hello, Alice!\"\n\n\u002F\u002F ❌ Impure: depends on external state (Date.now changes)\nconst getTimeGreeting = (name) => `Hello, ${name}, it's ${new Date().toISOString()}`;\n\u002F\u002F Not deterministic — different output each time (depends on current time)\n\n\u002F\u002F ❌ Impure: mutates the input (side effect)\nconst addItem = (list, item) => { list.push(item); return list; };\naddItem([1, 2], 3);  \u002F\u002F mutates the input array — caller's array is modified\n\n\u002F\u002F ✅ Pure: returns a new array (no mutation)\nconst addItemPure = (list, item) => [...list, item];\naddItemPure([1, 2], 3);  \u002F\u002F [1, 2, 3] — original array unchanged\n\n\u002F\u002F ── Why purity matters ──\n\u002F\u002F Pure functions are:\n\u002F\u002F   - Easy to test (no mocks needed — just call and check the return)\n\u002F\u002F   - Easy to cache (memoize — same input → same output, safe to cache)\n\u002F\u002F   - Easy to parallelize (no shared state → no race conditions)\n\u002F\u002F   - Easy to reason about (no hidden dependencies or side effects)\n","",[30,31,32,41,47,53,59,65,72,78,121,145,150,156,187,203,208,214,259,265,270,276,315,341,346,352,383,406,411,417,422,428,434,440],"code",{"__ignoreMap":28},[33,34,37],"span",{"class":35,"line":36},"line",1,[33,38,40],{"class":39},"sdCPZ","\u002F\u002F ── A pure function: same input → same output, no side effects ──\n",[33,42,44],{"class":35,"line":43},2,[33,45,46],{"class":39},"\u002F\u002F Pure functions are:\n",[33,48,50],{"class":35,"line":49},3,[33,51,52],{"class":39},"\u002F\u002F   - Deterministic (same input → same output, always)\n",[33,54,56],{"class":35,"line":55},4,[33,57,58],{"class":39},"\u002F\u002F   - Side-effect-free (no mutation of external state, no I\u002FO, no randomness)\n",[33,60,62],{"class":35,"line":61},5,[33,63,64],{"class":39},"\u002F\u002F   - Referentially transparent (can replace the call with its result)\n",[33,66,68],{"class":35,"line":67},6,[33,69,71],{"emptyLinePlaceholder":70},true,"\n",[33,73,75],{"class":35,"line":74},7,[33,76,77],{"class":39},"\u002F\u002F ✅ Pure function (deterministic, no side effects)\n",[33,79,81,85,89,92,96,100,103,106,109,112,115,118],{"class":35,"line":80},8,[33,82,84],{"class":83},"svdQ7","const",[33,86,88],{"class":87},"sIsaT"," add",[33,90,91],{"class":83}," =",[33,93,95],{"class":94},"ssxIu"," (",[33,97,99],{"class":98},"sCrzJ","a",[33,101,102],{"class":94},", ",[33,104,105],{"class":98},"b",[33,107,108],{"class":94},") ",[33,110,111],{"class":83},"=>",[33,113,114],{"class":94}," a ",[33,116,117],{"class":83},"+",[33,119,120],{"class":94}," b;\n",[33,122,124,127,130,134,136,139,142],{"class":35,"line":123},9,[33,125,126],{"class":87},"add",[33,128,129],{"class":94},"(",[33,131,133],{"class":132},"snvgF","1",[33,135,102],{"class":94},[33,137,138],{"class":132},"2",[33,140,141],{"class":94},");  ",[33,143,144],{"class":39},"\u002F\u002F always 3 — can replace with `3` anywhere (referential transparency)\n",[33,146,148],{"class":35,"line":147},10,[33,149,71],{"emptyLinePlaceholder":70},[33,151,153],{"class":35,"line":152},11,[33,154,155],{"class":39},"\u002F\u002F ✅ Pure: no external state, no mutation\n",[33,157,159,161,164,166,168,171,173,175,179,181,184],{"class":35,"line":158},12,[33,160,84],{"class":83},[33,162,163],{"class":87}," greet",[33,165,91],{"class":83},[33,167,95],{"class":94},[33,169,170],{"class":98},"name",[33,172,108],{"class":94},[33,174,111],{"class":83},[33,176,178],{"class":177},"sJ6F3"," `Hello, ${",[33,180,170],{"class":94},[33,182,183],{"class":177},"}!`",[33,185,186],{"class":94},";\n",[33,188,190,193,195,198,200],{"class":35,"line":189},13,[33,191,192],{"class":87},"greet",[33,194,129],{"class":94},[33,196,197],{"class":177},"\"Alice\"",[33,199,141],{"class":94},[33,201,202],{"class":39},"\u002F\u002F always \"Hello, Alice!\"\n",[33,204,206],{"class":35,"line":205},14,[33,207,71],{"emptyLinePlaceholder":70},[33,209,211],{"class":35,"line":210},15,[33,212,213],{"class":39},"\u002F\u002F ❌ Impure: depends on external state (Date.now changes)\n",[33,215,217,219,222,224,226,228,230,232,234,236,239,242,245,248,251,254,257],{"class":35,"line":216},16,[33,218,84],{"class":83},[33,220,221],{"class":87}," getTimeGreeting",[33,223,91],{"class":83},[33,225,95],{"class":94},[33,227,170],{"class":98},[33,229,108],{"class":94},[33,231,111],{"class":83},[33,233,178],{"class":177},[33,235,170],{"class":94},[33,237,238],{"class":177},"}, it's ${",[33,240,241],{"class":83},"new",[33,243,244],{"class":87}," Date",[33,246,247],{"class":177},"().",[33,249,250],{"class":87},"toISOString",[33,252,253],{"class":177},"()",[33,255,256],{"class":177},"}`",[33,258,186],{"class":94},[33,260,262],{"class":35,"line":261},17,[33,263,264],{"class":39},"\u002F\u002F Not deterministic — different output each time (depends on current time)\n",[33,266,268],{"class":35,"line":267},18,[33,269,71],{"emptyLinePlaceholder":70},[33,271,273],{"class":35,"line":272},19,[33,274,275],{"class":39},"\u002F\u002F ❌ Impure: mutates the input (side effect)\n",[33,277,279,281,284,286,288,291,293,296,298,300,303,306,309,312],{"class":35,"line":278},20,[33,280,84],{"class":83},[33,282,283],{"class":87}," addItem",[33,285,91],{"class":83},[33,287,95],{"class":94},[33,289,290],{"class":98},"list",[33,292,102],{"class":94},[33,294,295],{"class":98},"item",[33,297,108],{"class":94},[33,299,111],{"class":83},[33,301,302],{"class":94}," { list.",[33,304,305],{"class":87},"push",[33,307,308],{"class":94},"(item); ",[33,310,311],{"class":83},"return",[33,313,314],{"class":94}," list; };\n",[33,316,318,321,324,326,328,330,333,336,338],{"class":35,"line":317},21,[33,319,320],{"class":87},"addItem",[33,322,323],{"class":94},"([",[33,325,133],{"class":132},[33,327,102],{"class":94},[33,329,138],{"class":132},[33,331,332],{"class":94},"], ",[33,334,335],{"class":132},"3",[33,337,141],{"class":94},[33,339,340],{"class":39},"\u002F\u002F mutates the input array — caller's array is modified\n",[33,342,344],{"class":35,"line":343},22,[33,345,71],{"emptyLinePlaceholder":70},[33,347,349],{"class":35,"line":348},23,[33,350,351],{"class":39},"\u002F\u002F ✅ Pure: returns a new array (no mutation)\n",[33,353,355,357,360,362,364,366,368,370,372,374,377,380],{"class":35,"line":354},24,[33,356,84],{"class":83},[33,358,359],{"class":87}," addItemPure",[33,361,91],{"class":83},[33,363,95],{"class":94},[33,365,290],{"class":98},[33,367,102],{"class":94},[33,369,295],{"class":98},[33,371,108],{"class":94},[33,373,111],{"class":83},[33,375,376],{"class":94}," [",[33,378,379],{"class":83},"...",[33,381,382],{"class":94},"list, item];\n",[33,384,386,389,391,393,395,397,399,401,403],{"class":35,"line":385},25,[33,387,388],{"class":87},"addItemPure",[33,390,323],{"class":94},[33,392,133],{"class":132},[33,394,102],{"class":94},[33,396,138],{"class":132},[33,398,332],{"class":94},[33,400,335],{"class":132},[33,402,141],{"class":94},[33,404,405],{"class":39},"\u002F\u002F [1, 2, 3] — original array unchanged\n",[33,407,409],{"class":35,"line":408},26,[33,410,71],{"emptyLinePlaceholder":70},[33,412,414],{"class":35,"line":413},27,[33,415,416],{"class":39},"\u002F\u002F ── Why purity matters ──\n",[33,418,420],{"class":35,"line":419},28,[33,421,46],{"class":39},[33,423,425],{"class":35,"line":424},29,[33,426,427],{"class":39},"\u002F\u002F   - Easy to test (no mocks needed — just call and check the return)\n",[33,429,431],{"class":35,"line":430},30,[33,432,433],{"class":39},"\u002F\u002F   - Easy to cache (memoize — same input → same output, safe to cache)\n",[33,435,437],{"class":35,"line":436},31,[33,438,439],{"class":39},"\u002F\u002F   - Easy to parallelize (no shared state → no race conditions)\n",[33,441,443],{"class":35,"line":442},32,[33,444,445],{"class":39},"\u002F\u002F   - Easy to reason about (no hidden dependencies or side effects)\n",[15,447,449],{"id":448},"immutability-patterns","Immutability Patterns",[20,451,452],{"language":22},[24,453,455],{"className":26,"code":454,"language":22,"meta":28,"style":28},"\u002F\u002F ── Immutable update patterns (never mutate — always create new structures) ──\n\n\u002F\u002F ── Object updates ──\nconst user = { name: \"Alice\", age: 30 };\n\u002F\u002F ❌ Mutable: user.age = 31;\n\u002F\u002F ✅ Immutable: spread + override\nconst updatedUser = { ...user, age: 31 };  \u002F\u002F new object, original unchanged\n\n\u002F\u002F ── Nested object updates ──\nconst state = { user: { profile: { name: \"Alice\" } } };\n\u002F\u002F ✅ Immutable nested update (spread at each level):\nconst newState = {\n    ...state,\n    user: { ...state.user, profile: { ...state.user.profile, name: \"Bob\" } },\n};\n\n\u002F\u002F ── Array updates ──\nconst items = [1, 2, 3];\n\u002F\u002F Add: [...items, 4]\n\u002F\u002F Remove: items.filter(x => x !== 2)  → [1, 3]\n\u002F\u002F Update: items.map(x => x === 2 ? 99 : x)  → [1, 99, 3]\n\u002F\u002F Insert at index: [...items.slice(0, 1), 99, ...items.slice(1)]  → [1, 99, 2, 3]\n\n\u002F\u002F ── Immutable update at a nested array index ──\nconst lists = [{ id: 1, name: \"A\" }, { id: 2, name: \"B\" }];\nconst updated = lists.map(item =>\n    item.id === 2 ? { ...item, name: \"B updated\" } : item\n);\n\u002F\u002F → [{ id: 1, name: \"A\" }, { id: 2, name: \"B updated\" }] (original unchanged)\n\n\u002F\u002F ── Freeze for immutability enforcement (dev mode) ──\nconst frozen = Object.freeze({ count: 0, nested: { value: 1 } });\n\u002F\u002F frozen.count = 1;  \u002F\u002F silently fails (strict mode: TypeError)\n\u002F\u002F frozen.nested.value = 2;  \u002F\u002F ⚠️ works! (freeze is shallow — nested is not frozen)\n",[30,456,457,462,466,471,494,499,504,530,534,539,556,561,573,581,602,607,611,616,640,645,650,655,660,664,669,702,724,757,762,767,771,776,805,814],{"__ignoreMap":28},[33,458,459],{"class":35,"line":36},[33,460,461],{"class":39},"\u002F\u002F ── Immutable update patterns (never mutate — always create new structures) ──\n",[33,463,464],{"class":35,"line":43},[33,465,71],{"emptyLinePlaceholder":70},[33,467,468],{"class":35,"line":49},[33,469,470],{"class":39},"\u002F\u002F ── Object updates ──\n",[33,472,473,475,478,480,483,485,488,491],{"class":35,"line":55},[33,474,84],{"class":83},[33,476,477],{"class":132}," user",[33,479,91],{"class":83},[33,481,482],{"class":94}," { name: ",[33,484,197],{"class":177},[33,486,487],{"class":94},", age: ",[33,489,490],{"class":132},"30",[33,492,493],{"class":94}," };\n",[33,495,496],{"class":35,"line":61},[33,497,498],{"class":39},"\u002F\u002F ❌ Mutable: user.age = 31;\n",[33,500,501],{"class":35,"line":67},[33,502,503],{"class":39},"\u002F\u002F ✅ Immutable: spread + override\n",[33,505,506,508,511,513,516,518,521,524,527],{"class":35,"line":74},[33,507,84],{"class":83},[33,509,510],{"class":132}," updatedUser",[33,512,91],{"class":83},[33,514,515],{"class":94}," { ",[33,517,379],{"class":83},[33,519,520],{"class":94},"user, age: ",[33,522,523],{"class":132},"31",[33,525,526],{"class":94}," };  ",[33,528,529],{"class":39},"\u002F\u002F new object, original unchanged\n",[33,531,532],{"class":35,"line":80},[33,533,71],{"emptyLinePlaceholder":70},[33,535,536],{"class":35,"line":123},[33,537,538],{"class":39},"\u002F\u002F ── Nested object updates ──\n",[33,540,541,543,546,548,551,553],{"class":35,"line":147},[33,542,84],{"class":83},[33,544,545],{"class":132}," state",[33,547,91],{"class":83},[33,549,550],{"class":94}," { user: { profile: { name: ",[33,552,197],{"class":177},[33,554,555],{"class":94}," } } };\n",[33,557,558],{"class":35,"line":152},[33,559,560],{"class":39},"\u002F\u002F ✅ Immutable nested update (spread at each level):\n",[33,562,563,565,568,570],{"class":35,"line":158},[33,564,84],{"class":83},[33,566,567],{"class":132}," newState",[33,569,91],{"class":83},[33,571,572],{"class":94}," {\n",[33,574,575,578],{"class":35,"line":189},[33,576,577],{"class":83},"    ...",[33,579,580],{"class":94},"state,\n",[33,582,583,586,588,591,593,596,599],{"class":35,"line":205},[33,584,585],{"class":94},"    user: { ",[33,587,379],{"class":83},[33,589,590],{"class":94},"state.user, profile: { ",[33,592,379],{"class":83},[33,594,595],{"class":94},"state.user.profile, name: ",[33,597,598],{"class":177},"\"Bob\"",[33,600,601],{"class":94}," } },\n",[33,603,604],{"class":35,"line":210},[33,605,606],{"class":94},"};\n",[33,608,609],{"class":35,"line":216},[33,610,71],{"emptyLinePlaceholder":70},[33,612,613],{"class":35,"line":261},[33,614,615],{"class":39},"\u002F\u002F ── Array updates ──\n",[33,617,618,620,623,625,627,629,631,633,635,637],{"class":35,"line":267},[33,619,84],{"class":83},[33,621,622],{"class":132}," items",[33,624,91],{"class":83},[33,626,376],{"class":94},[33,628,133],{"class":132},[33,630,102],{"class":94},[33,632,138],{"class":132},[33,634,102],{"class":94},[33,636,335],{"class":132},[33,638,639],{"class":94},"];\n",[33,641,642],{"class":35,"line":272},[33,643,644],{"class":39},"\u002F\u002F Add: [...items, 4]\n",[33,646,647],{"class":35,"line":278},[33,648,649],{"class":39},"\u002F\u002F Remove: items.filter(x => x !== 2)  → [1, 3]\n",[33,651,652],{"class":35,"line":317},[33,653,654],{"class":39},"\u002F\u002F Update: items.map(x => x === 2 ? 99 : x)  → [1, 99, 3]\n",[33,656,657],{"class":35,"line":343},[33,658,659],{"class":39},"\u002F\u002F Insert at index: [...items.slice(0, 1), 99, ...items.slice(1)]  → [1, 99, 2, 3]\n",[33,661,662],{"class":35,"line":348},[33,663,71],{"emptyLinePlaceholder":70},[33,665,666],{"class":35,"line":354},[33,667,668],{"class":39},"\u002F\u002F ── Immutable update at a nested array index ──\n",[33,670,671,673,676,678,681,683,686,689,692,694,696,699],{"class":35,"line":385},[33,672,84],{"class":83},[33,674,675],{"class":132}," lists",[33,677,91],{"class":83},[33,679,680],{"class":94}," [{ id: ",[33,682,133],{"class":132},[33,684,685],{"class":94},", name: ",[33,687,688],{"class":177},"\"A\"",[33,690,691],{"class":94}," }, { id: ",[33,693,138],{"class":132},[33,695,685],{"class":94},[33,697,698],{"class":177},"\"B\"",[33,700,701],{"class":94}," }];\n",[33,703,704,706,709,711,714,717,719,721],{"class":35,"line":408},[33,705,84],{"class":83},[33,707,708],{"class":132}," updated",[33,710,91],{"class":83},[33,712,713],{"class":94}," lists.",[33,715,716],{"class":87},"map",[33,718,129],{"class":94},[33,720,295],{"class":98},[33,722,723],{"class":83}," =>\n",[33,725,726,729,732,735,738,740,742,745,748,751,754],{"class":35,"line":413},[33,727,728],{"class":94},"    item.id ",[33,730,731],{"class":83},"===",[33,733,734],{"class":132}," 2",[33,736,737],{"class":83}," ?",[33,739,515],{"class":94},[33,741,379],{"class":83},[33,743,744],{"class":94},"item, name: ",[33,746,747],{"class":177},"\"B updated\"",[33,749,750],{"class":94}," } ",[33,752,753],{"class":83},":",[33,755,756],{"class":94}," item\n",[33,758,759],{"class":35,"line":419},[33,760,761],{"class":94},");\n",[33,763,764],{"class":35,"line":424},[33,765,766],{"class":39},"\u002F\u002F → [{ id: 1, name: \"A\" }, { id: 2, name: \"B updated\" }] (original unchanged)\n",[33,768,769],{"class":35,"line":430},[33,770,71],{"emptyLinePlaceholder":70},[33,772,773],{"class":35,"line":436},[33,774,775],{"class":39},"\u002F\u002F ── Freeze for immutability enforcement (dev mode) ──\n",[33,777,778,780,783,785,788,791,794,797,800,802],{"class":35,"line":442},[33,779,84],{"class":83},[33,781,782],{"class":132}," frozen",[33,784,91],{"class":83},[33,786,787],{"class":94}," Object.",[33,789,790],{"class":87},"freeze",[33,792,793],{"class":94},"({ count: ",[33,795,796],{"class":132},"0",[33,798,799],{"class":94},", nested: { value: ",[33,801,133],{"class":132},[33,803,804],{"class":94}," } });\n",[33,806,808,811],{"class":35,"line":807},33,[33,809,810],{"class":39},"\u002F\u002F frozen.count = 1;",[33,812,813],{"class":39},"  \u002F\u002F silently fails (strict mode: TypeError)\n",[33,815,817,820],{"class":35,"line":816},34,[33,818,819],{"class":39},"\u002F\u002F frozen.nested.value = 2;",[33,821,822],{"class":39},"  \u002F\u002F ⚠️ works! (freeze is shallow — nested is not frozen)\n",[15,824,826],{"id":825},"the-either-monad-for-error-handling","The Either Monad for Error Handling",[20,828,829],{"language":22},[24,830,832],{"className":26,"code":831,"language":22,"meta":28,"style":28},"\u002F\u002F ── Either: represent success (Right) or failure (Left) without throwing ──\n\u002F\u002F Instead of try\u002Fcatch, use a value that represents success or failure.\n\nconst Left = (value) => ({\n    map: () => Left(value),  \u002F\u002F Left short-circuits (skips the operation)\n    chain: () => Left(value),  \u002F\u002F same for chain (flatMap)\n    fold: (onLeft, _) => onLeft(value),  \u002F\u002F run the error handler\n    getOrElse: (fallback) => fallback,\n    isLeft: true,\n    value,\n});\n\nconst Right = (value) => ({\n    map: (fn) => Right(fn(value)),  \u002F\u002F Right applies the function\n    chain: (fn) => fn(value),  \u002F\u002F chain (flatMap): returns a new Either\n    fold: (_, onRight) => onRight(value),  \u002F\u002F run the success handler\n    getOrElse: () => value,\n    isLeft: false,\n    value,\n});\n\n\u002F\u002F ── Usage: validate without try\u002Fcatch ──\nconst parseJSON = (str) => {\n    try {\n        return Right(JSON.parse(str));\n    } catch (e) {\n        return Left(e.message);\n    }\n};\n\nconst result = parseJSON('{\"name\": \"Alice\"}')\n    .map(obj => obj.name)\n    .map(name => name.toUpperCase())\n    .fold(\n        err => `Error: ${err}`,\n        name => `Success: ${name}`\n    );\nconsole.log(result);  \u002F\u002F \"Success: ALICE\"\n\nconst failed = parseJSON('invalid')\n    .map(obj => obj.name)  \u002F\u002F skipped (Left short-circuits)\n    .fold(\n        err => `Error: ${err}`,\n        name => `Success: ${name}`\n    );\nconsole.log(failed);  \u002F\u002F \"Error: Unexpected token 'i' at...\" (Left propagated)\n",[30,833,834,839,844,848,869,887,903,931,948,959,964,969,973,992,1017,1037,1062,1073,1082,1086,1090,1094,1099,1119,1126,1147,1158,1167,1172,1176,1180,1199,1217,1238,1248,1266,1282,1288,1303,1308,1327,1346,1355,1370,1383,1388],{"__ignoreMap":28},[33,835,836],{"class":35,"line":36},[33,837,838],{"class":39},"\u002F\u002F ── Either: represent success (Right) or failure (Left) without throwing ──\n",[33,840,841],{"class":35,"line":43},[33,842,843],{"class":39},"\u002F\u002F Instead of try\u002Fcatch, use a value that represents success or failure.\n",[33,845,846],{"class":35,"line":49},[33,847,71],{"emptyLinePlaceholder":70},[33,849,850,852,855,857,859,862,864,866],{"class":35,"line":55},[33,851,84],{"class":83},[33,853,854],{"class":87}," Left",[33,856,91],{"class":83},[33,858,95],{"class":94},[33,860,861],{"class":98},"value",[33,863,108],{"class":94},[33,865,111],{"class":83},[33,867,868],{"class":94}," ({\n",[33,870,871,874,877,879,881,884],{"class":35,"line":61},[33,872,873],{"class":87},"    map",[33,875,876],{"class":94},": () ",[33,878,111],{"class":83},[33,880,854],{"class":87},[33,882,883],{"class":94},"(value),  ",[33,885,886],{"class":39},"\u002F\u002F Left short-circuits (skips the operation)\n",[33,888,889,892,894,896,898,900],{"class":35,"line":67},[33,890,891],{"class":87},"    chain",[33,893,876],{"class":94},[33,895,111],{"class":83},[33,897,854],{"class":87},[33,899,883],{"class":94},[33,901,902],{"class":39},"\u002F\u002F same for chain (flatMap)\n",[33,904,905,908,911,914,916,919,921,923,926,928],{"class":35,"line":74},[33,906,907],{"class":87},"    fold",[33,909,910],{"class":94},": (",[33,912,913],{"class":98},"onLeft",[33,915,102],{"class":94},[33,917,918],{"class":98},"_",[33,920,108],{"class":94},[33,922,111],{"class":83},[33,924,925],{"class":87}," onLeft",[33,927,883],{"class":94},[33,929,930],{"class":39},"\u002F\u002F run the error handler\n",[33,932,933,936,938,941,943,945],{"class":35,"line":80},[33,934,935],{"class":87},"    getOrElse",[33,937,910],{"class":94},[33,939,940],{"class":98},"fallback",[33,942,108],{"class":94},[33,944,111],{"class":83},[33,946,947],{"class":94}," fallback,\n",[33,949,950,953,956],{"class":35,"line":123},[33,951,952],{"class":94},"    isLeft: ",[33,954,955],{"class":132},"true",[33,957,958],{"class":94},",\n",[33,960,961],{"class":35,"line":147},[33,962,963],{"class":94},"    value,\n",[33,965,966],{"class":35,"line":152},[33,967,968],{"class":94},"});\n",[33,970,971],{"class":35,"line":158},[33,972,71],{"emptyLinePlaceholder":70},[33,974,975,977,980,982,984,986,988,990],{"class":35,"line":189},[33,976,84],{"class":83},[33,978,979],{"class":87}," Right",[33,981,91],{"class":83},[33,983,95],{"class":94},[33,985,861],{"class":98},[33,987,108],{"class":94},[33,989,111],{"class":83},[33,991,868],{"class":94},[33,993,994,996,998,1001,1003,1005,1007,1009,1011,1014],{"class":35,"line":205},[33,995,873],{"class":87},[33,997,910],{"class":94},[33,999,1000],{"class":98},"fn",[33,1002,108],{"class":94},[33,1004,111],{"class":83},[33,1006,979],{"class":87},[33,1008,129],{"class":94},[33,1010,1000],{"class":87},[33,1012,1013],{"class":94},"(value)),  ",[33,1015,1016],{"class":39},"\u002F\u002F Right applies the function\n",[33,1018,1019,1021,1023,1025,1027,1029,1032,1034],{"class":35,"line":210},[33,1020,891],{"class":87},[33,1022,910],{"class":94},[33,1024,1000],{"class":98},[33,1026,108],{"class":94},[33,1028,111],{"class":83},[33,1030,1031],{"class":87}," fn",[33,1033,883],{"class":94},[33,1035,1036],{"class":39},"\u002F\u002F chain (flatMap): returns a new Either\n",[33,1038,1039,1041,1043,1045,1047,1050,1052,1054,1057,1059],{"class":35,"line":216},[33,1040,907],{"class":87},[33,1042,910],{"class":94},[33,1044,918],{"class":98},[33,1046,102],{"class":94},[33,1048,1049],{"class":98},"onRight",[33,1051,108],{"class":94},[33,1053,111],{"class":83},[33,1055,1056],{"class":87}," onRight",[33,1058,883],{"class":94},[33,1060,1061],{"class":39},"\u002F\u002F run the success handler\n",[33,1063,1064,1066,1068,1070],{"class":35,"line":261},[33,1065,935],{"class":87},[33,1067,876],{"class":94},[33,1069,111],{"class":83},[33,1071,1072],{"class":94}," value,\n",[33,1074,1075,1077,1080],{"class":35,"line":267},[33,1076,952],{"class":94},[33,1078,1079],{"class":132},"false",[33,1081,958],{"class":94},[33,1083,1084],{"class":35,"line":272},[33,1085,963],{"class":94},[33,1087,1088],{"class":35,"line":278},[33,1089,968],{"class":94},[33,1091,1092],{"class":35,"line":317},[33,1093,71],{"emptyLinePlaceholder":70},[33,1095,1096],{"class":35,"line":343},[33,1097,1098],{"class":39},"\u002F\u002F ── Usage: validate without try\u002Fcatch ──\n",[33,1100,1101,1103,1106,1108,1110,1113,1115,1117],{"class":35,"line":348},[33,1102,84],{"class":83},[33,1104,1105],{"class":87}," parseJSON",[33,1107,91],{"class":83},[33,1109,95],{"class":94},[33,1111,1112],{"class":98},"str",[33,1114,108],{"class":94},[33,1116,111],{"class":83},[33,1118,572],{"class":94},[33,1120,1121,1124],{"class":35,"line":354},[33,1122,1123],{"class":83},"    try",[33,1125,572],{"class":94},[33,1127,1128,1131,1133,1135,1138,1141,1144],{"class":35,"line":385},[33,1129,1130],{"class":83},"        return",[33,1132,979],{"class":87},[33,1134,129],{"class":94},[33,1136,1137],{"class":132},"JSON",[33,1139,1140],{"class":94},".",[33,1142,1143],{"class":87},"parse",[33,1145,1146],{"class":94},"(str));\n",[33,1148,1149,1152,1155],{"class":35,"line":408},[33,1150,1151],{"class":94},"    } ",[33,1153,1154],{"class":83},"catch",[33,1156,1157],{"class":94}," (e) {\n",[33,1159,1160,1162,1164],{"class":35,"line":413},[33,1161,1130],{"class":83},[33,1163,854],{"class":87},[33,1165,1166],{"class":94},"(e.message);\n",[33,1168,1169],{"class":35,"line":419},[33,1170,1171],{"class":94},"    }\n",[33,1173,1174],{"class":35,"line":424},[33,1175,606],{"class":94},[33,1177,1178],{"class":35,"line":430},[33,1179,71],{"emptyLinePlaceholder":70},[33,1181,1182,1184,1187,1189,1191,1193,1196],{"class":35,"line":436},[33,1183,84],{"class":83},[33,1185,1186],{"class":132}," result",[33,1188,91],{"class":83},[33,1190,1105],{"class":87},[33,1192,129],{"class":94},[33,1194,1195],{"class":177},"'{\"name\": \"Alice\"}'",[33,1197,1198],{"class":94},")\n",[33,1200,1201,1204,1206,1208,1211,1214],{"class":35,"line":442},[33,1202,1203],{"class":94},"    .",[33,1205,716],{"class":87},[33,1207,129],{"class":94},[33,1209,1210],{"class":98},"obj",[33,1212,1213],{"class":83}," =>",[33,1215,1216],{"class":94}," obj.name)\n",[33,1218,1219,1221,1223,1225,1227,1229,1232,1235],{"class":35,"line":807},[33,1220,1203],{"class":94},[33,1222,716],{"class":87},[33,1224,129],{"class":94},[33,1226,170],{"class":98},[33,1228,1213],{"class":83},[33,1230,1231],{"class":94}," name.",[33,1233,1234],{"class":87},"toUpperCase",[33,1236,1237],{"class":94},"())\n",[33,1239,1240,1242,1245],{"class":35,"line":816},[33,1241,1203],{"class":94},[33,1243,1244],{"class":87},"fold",[33,1246,1247],{"class":94},"(\n",[33,1249,1251,1254,1256,1259,1262,1264],{"class":35,"line":1250},35,[33,1252,1253],{"class":98},"        err",[33,1255,1213],{"class":83},[33,1257,1258],{"class":177}," `Error: ${",[33,1260,1261],{"class":94},"err",[33,1263,256],{"class":177},[33,1265,958],{"class":94},[33,1267,1269,1272,1274,1277,1279],{"class":35,"line":1268},36,[33,1270,1271],{"class":98},"        name",[33,1273,1213],{"class":83},[33,1275,1276],{"class":177}," `Success: ${",[33,1278,170],{"class":94},[33,1280,1281],{"class":177},"}`\n",[33,1283,1285],{"class":35,"line":1284},37,[33,1286,1287],{"class":94},"    );\n",[33,1289,1291,1294,1297,1300],{"class":35,"line":1290},38,[33,1292,1293],{"class":94},"console.",[33,1295,1296],{"class":87},"log",[33,1298,1299],{"class":94},"(result);  ",[33,1301,1302],{"class":39},"\u002F\u002F \"Success: ALICE\"\n",[33,1304,1306],{"class":35,"line":1305},39,[33,1307,71],{"emptyLinePlaceholder":70},[33,1309,1311,1313,1316,1318,1320,1322,1325],{"class":35,"line":1310},40,[33,1312,84],{"class":83},[33,1314,1315],{"class":132}," failed",[33,1317,91],{"class":83},[33,1319,1105],{"class":87},[33,1321,129],{"class":94},[33,1323,1324],{"class":177},"'invalid'",[33,1326,1198],{"class":94},[33,1328,1330,1332,1334,1336,1338,1340,1343],{"class":35,"line":1329},41,[33,1331,1203],{"class":94},[33,1333,716],{"class":87},[33,1335,129],{"class":94},[33,1337,1210],{"class":98},[33,1339,1213],{"class":83},[33,1341,1342],{"class":94}," obj.name)  ",[33,1344,1345],{"class":39},"\u002F\u002F skipped (Left short-circuits)\n",[33,1347,1349,1351,1353],{"class":35,"line":1348},42,[33,1350,1203],{"class":94},[33,1352,1244],{"class":87},[33,1354,1247],{"class":94},[33,1356,1358,1360,1362,1364,1366,1368],{"class":35,"line":1357},43,[33,1359,1253],{"class":98},[33,1361,1213],{"class":83},[33,1363,1258],{"class":177},[33,1365,1261],{"class":94},[33,1367,256],{"class":177},[33,1369,958],{"class":94},[33,1371,1373,1375,1377,1379,1381],{"class":35,"line":1372},44,[33,1374,1271],{"class":98},[33,1376,1213],{"class":83},[33,1378,1276],{"class":177},[33,1380,170],{"class":94},[33,1382,1281],{"class":177},[33,1384,1386],{"class":35,"line":1385},45,[33,1387,1287],{"class":94},[33,1389,1391,1393,1395,1398],{"class":35,"line":1390},46,[33,1392,1293],{"class":94},[33,1394,1296],{"class":87},[33,1396,1397],{"class":94},"(failed);  ",[33,1399,1400],{"class":39},"\u002F\u002F \"Error: Unexpected token 'i' at...\" (Left propagated)\n",[15,1402,1404],{"id":1403},"production-pattern-immutable-state-updates-redux-style","Production Pattern: Immutable State Updates (Redux-style)",[20,1406,1407],{"language":22},[24,1408,1410],{"className":26,"code":1409,"language":22,"meta":28,"style":28},"\u002F\u002F ── Reducer pattern: pure function that produces a new state ──\nconst initialState = {\n    items: [],\n    loading: false,\n    error: null,\n};\n\nfunction reducer(state = initialState, action) {\n    switch (action.type) {\n        case \"FETCH_START\":\n            return { ...state, loading: true, error: null };\n        case \"FETCH_SUCCESS\":\n            return { ...state, loading: false, items: action.payload };\n        case \"FETCH_ERROR\":\n            return { ...state, loading: false, error: action.payload };\n        case \"ADD_ITEM\":\n            return { ...state, items: [...state.items, action.payload] };\n        case \"UPDATE_ITEM\":\n            return {\n                ...state,\n                items: state.items.map(item =>\n                    item.id === action.payload.id ? { ...item, ...action.payload } : item\n                ),\n            };\n        case \"REMOVE_ITEM\":\n            return {\n                ...state,\n                items: state.items.filter(item => item.id !== action.payload),\n            };\n        default:\n            return state;  \u002F\u002F pure: return same state for unknown actions\n    }\n}\n\n\u002F\u002F ── State transitions are predictable and testable ──\nconst s1 = reducer(initialState, { type: \"ADD_ITEM\", payload: { id: 1, name: \"A\" } });\nconst s2 = reducer(s1, { type: \"ADD_ITEM\", payload: { id: 2, name: \"B\" } });\nconst s3 = reducer(s2, { type: \"REMOVE_ITEM\", payload: 1 });\nconsole.log(s3.items);  \u002F\u002F [{ id: 2, name: \"B\" }]\n\u002F\u002F Each state is a new object — previous states are unchanged (can time-travel debug).\n",[30,1411,1412,1417,1428,1433,1442,1452,1456,1460,1484,1492,1503,1524,1533,1548,1557,1572,1581,1597,1606,1612,1619,1632,1661,1666,1671,1680,1686,1692,1714,1718,1725,1735,1739,1744,1748,1753,1781,1807,1832,1844],{"__ignoreMap":28},[33,1413,1414],{"class":35,"line":36},[33,1415,1416],{"class":39},"\u002F\u002F ── Reducer pattern: pure function that produces a new state ──\n",[33,1418,1419,1421,1424,1426],{"class":35,"line":43},[33,1420,84],{"class":83},[33,1422,1423],{"class":132}," initialState",[33,1425,91],{"class":83},[33,1427,572],{"class":94},[33,1429,1430],{"class":35,"line":49},[33,1431,1432],{"class":94},"    items: [],\n",[33,1434,1435,1438,1440],{"class":35,"line":55},[33,1436,1437],{"class":94},"    loading: ",[33,1439,1079],{"class":132},[33,1441,958],{"class":94},[33,1443,1444,1447,1450],{"class":35,"line":61},[33,1445,1446],{"class":94},"    error: ",[33,1448,1449],{"class":132},"null",[33,1451,958],{"class":94},[33,1453,1454],{"class":35,"line":67},[33,1455,606],{"class":94},[33,1457,1458],{"class":35,"line":74},[33,1459,71],{"emptyLinePlaceholder":70},[33,1461,1462,1465,1468,1470,1473,1475,1478,1481],{"class":35,"line":80},[33,1463,1464],{"class":83},"function",[33,1466,1467],{"class":87}," reducer",[33,1469,129],{"class":94},[33,1471,1472],{"class":98},"state",[33,1474,91],{"class":83},[33,1476,1477],{"class":94}," initialState, ",[33,1479,1480],{"class":98},"action",[33,1482,1483],{"class":94},") {\n",[33,1485,1486,1489],{"class":35,"line":123},[33,1487,1488],{"class":83},"    switch",[33,1490,1491],{"class":94}," (action.type) {\n",[33,1493,1494,1497,1500],{"class":35,"line":147},[33,1495,1496],{"class":83},"        case",[33,1498,1499],{"class":177}," \"FETCH_START\"",[33,1501,1502],{"class":94},":\n",[33,1504,1505,1508,1510,1512,1515,1517,1520,1522],{"class":35,"line":152},[33,1506,1507],{"class":83},"            return",[33,1509,515],{"class":94},[33,1511,379],{"class":83},[33,1513,1514],{"class":94},"state, loading: ",[33,1516,955],{"class":132},[33,1518,1519],{"class":94},", error: ",[33,1521,1449],{"class":132},[33,1523,493],{"class":94},[33,1525,1526,1528,1531],{"class":35,"line":158},[33,1527,1496],{"class":83},[33,1529,1530],{"class":177}," \"FETCH_SUCCESS\"",[33,1532,1502],{"class":94},[33,1534,1535,1537,1539,1541,1543,1545],{"class":35,"line":189},[33,1536,1507],{"class":83},[33,1538,515],{"class":94},[33,1540,379],{"class":83},[33,1542,1514],{"class":94},[33,1544,1079],{"class":132},[33,1546,1547],{"class":94},", items: action.payload };\n",[33,1549,1550,1552,1555],{"class":35,"line":205},[33,1551,1496],{"class":83},[33,1553,1554],{"class":177}," \"FETCH_ERROR\"",[33,1556,1502],{"class":94},[33,1558,1559,1561,1563,1565,1567,1569],{"class":35,"line":210},[33,1560,1507],{"class":83},[33,1562,515],{"class":94},[33,1564,379],{"class":83},[33,1566,1514],{"class":94},[33,1568,1079],{"class":132},[33,1570,1571],{"class":94},", error: action.payload };\n",[33,1573,1574,1576,1579],{"class":35,"line":216},[33,1575,1496],{"class":83},[33,1577,1578],{"class":177}," \"ADD_ITEM\"",[33,1580,1502],{"class":94},[33,1582,1583,1585,1587,1589,1592,1594],{"class":35,"line":261},[33,1584,1507],{"class":83},[33,1586,515],{"class":94},[33,1588,379],{"class":83},[33,1590,1591],{"class":94},"state, items: [",[33,1593,379],{"class":83},[33,1595,1596],{"class":94},"state.items, action.payload] };\n",[33,1598,1599,1601,1604],{"class":35,"line":267},[33,1600,1496],{"class":83},[33,1602,1603],{"class":177}," \"UPDATE_ITEM\"",[33,1605,1502],{"class":94},[33,1607,1608,1610],{"class":35,"line":272},[33,1609,1507],{"class":83},[33,1611,572],{"class":94},[33,1613,1614,1617],{"class":35,"line":278},[33,1615,1616],{"class":83},"                ...",[33,1618,580],{"class":94},[33,1620,1621,1624,1626,1628,1630],{"class":35,"line":317},[33,1622,1623],{"class":94},"                items: state.items.",[33,1625,716],{"class":87},[33,1627,129],{"class":94},[33,1629,295],{"class":98},[33,1631,723],{"class":83},[33,1633,1634,1637,1639,1642,1645,1647,1649,1652,1654,1657,1659],{"class":35,"line":343},[33,1635,1636],{"class":94},"                    item.id ",[33,1638,731],{"class":83},[33,1640,1641],{"class":94}," action.payload.id ",[33,1643,1644],{"class":83},"?",[33,1646,515],{"class":94},[33,1648,379],{"class":83},[33,1650,1651],{"class":94},"item, ",[33,1653,379],{"class":83},[33,1655,1656],{"class":94},"action.payload } ",[33,1658,753],{"class":83},[33,1660,756],{"class":94},[33,1662,1663],{"class":35,"line":348},[33,1664,1665],{"class":94},"                ),\n",[33,1667,1668],{"class":35,"line":354},[33,1669,1670],{"class":94},"            };\n",[33,1672,1673,1675,1678],{"class":35,"line":385},[33,1674,1496],{"class":83},[33,1676,1677],{"class":177}," \"REMOVE_ITEM\"",[33,1679,1502],{"class":94},[33,1681,1682,1684],{"class":35,"line":408},[33,1683,1507],{"class":83},[33,1685,572],{"class":94},[33,1687,1688,1690],{"class":35,"line":413},[33,1689,1616],{"class":83},[33,1691,580],{"class":94},[33,1693,1694,1696,1699,1701,1703,1705,1708,1711],{"class":35,"line":419},[33,1695,1623],{"class":94},[33,1697,1698],{"class":87},"filter",[33,1700,129],{"class":94},[33,1702,295],{"class":98},[33,1704,1213],{"class":83},[33,1706,1707],{"class":94}," item.id ",[33,1709,1710],{"class":83},"!==",[33,1712,1713],{"class":94}," action.payload),\n",[33,1715,1716],{"class":35,"line":424},[33,1717,1670],{"class":94},[33,1719,1720,1723],{"class":35,"line":430},[33,1721,1722],{"class":83},"        default",[33,1724,1502],{"class":94},[33,1726,1727,1729,1732],{"class":35,"line":436},[33,1728,1507],{"class":83},[33,1730,1731],{"class":94}," state;  ",[33,1733,1734],{"class":39},"\u002F\u002F pure: return same state for unknown actions\n",[33,1736,1737],{"class":35,"line":442},[33,1738,1171],{"class":94},[33,1740,1741],{"class":35,"line":807},[33,1742,1743],{"class":94},"}\n",[33,1745,1746],{"class":35,"line":816},[33,1747,71],{"emptyLinePlaceholder":70},[33,1749,1750],{"class":35,"line":1250},[33,1751,1752],{"class":39},"\u002F\u002F ── State transitions are predictable and testable ──\n",[33,1754,1755,1757,1760,1762,1764,1767,1770,1773,1775,1777,1779],{"class":35,"line":1268},[33,1756,84],{"class":83},[33,1758,1759],{"class":132}," s1",[33,1761,91],{"class":83},[33,1763,1467],{"class":87},[33,1765,1766],{"class":94},"(initialState, { type: ",[33,1768,1769],{"class":177},"\"ADD_ITEM\"",[33,1771,1772],{"class":94},", payload: { id: ",[33,1774,133],{"class":132},[33,1776,685],{"class":94},[33,1778,688],{"class":177},[33,1780,804],{"class":94},[33,1782,1783,1785,1788,1790,1792,1795,1797,1799,1801,1803,1805],{"class":35,"line":1284},[33,1784,84],{"class":83},[33,1786,1787],{"class":132}," s2",[33,1789,91],{"class":83},[33,1791,1467],{"class":87},[33,1793,1794],{"class":94},"(s1, { type: ",[33,1796,1769],{"class":177},[33,1798,1772],{"class":94},[33,1800,138],{"class":132},[33,1802,685],{"class":94},[33,1804,698],{"class":177},[33,1806,804],{"class":94},[33,1808,1809,1811,1814,1816,1818,1821,1824,1827,1829],{"class":35,"line":1290},[33,1810,84],{"class":83},[33,1812,1813],{"class":132}," s3",[33,1815,91],{"class":83},[33,1817,1467],{"class":87},[33,1819,1820],{"class":94},"(s2, { type: ",[33,1822,1823],{"class":177},"\"REMOVE_ITEM\"",[33,1825,1826],{"class":94},", payload: ",[33,1828,133],{"class":132},[33,1830,1831],{"class":94}," });\n",[33,1833,1834,1836,1838,1841],{"class":35,"line":1305},[33,1835,1293],{"class":94},[33,1837,1296],{"class":87},[33,1839,1840],{"class":94},"(s3.items);  ",[33,1842,1843],{"class":39},"\u002F\u002F [{ id: 2, name: \"B\" }]\n",[33,1845,1846],{"class":35,"line":1310},[33,1847,1848],{"class":39},"\u002F\u002F Each state is a new object — previous states are unchanged (can time-travel debug).\n",[15,1850,1852],{"id":1851},"tips-tricks","💡 Tips & Tricks",[20,1854,1855],{"language":22},[24,1856,1858],{"className":26,"code":1857,"language":22,"meta":28,"style":28},"\u002F\u002F ── Function composition (pipe and compose) ──\nconst pipe = (...fns) => (x) => fns.reduce((acc, fn) => fn(acc), x);\nconst compose = (...fns) => (x) => fns.reduceRight((acc, fn) => fn(acc), x);\n\nconst formatName = pipe(\n    name => name.trim(),\n    name => name.toLowerCase(),\n    name => name.replace(\u002F\\b\\w\u002Fg, c => c.toUpperCase()),  \u002F\u002F title case\n);\nformatName(\"  aLICE jones  \");  \u002F\u002F \"Alice Jones\"\n\n\u002F\u002F ── Currying for reusable partial functions ──\nconst curry = (fn) => (...args) =>\n    args.length >= fn.length ? fn(...args) : curry(fn.bind(null, ...args));\n\nconst log = curry((level, message) => console.log(`[${level}] ${message}`));\nconst info = log(\"INFO\");\nconst error = log(\"ERROR\");\ninfo(\"started\");   \u002F\u002F [INFO] started\nerror(\"crashed\");  \u002F\u002F [ERROR] crashed\n\n\u002F\u002F ── Lens pattern for immutable deep updates ──\nconst lens = (get, set) => ({ get, set });\nconst propLens = (key) => lens(\n    obj => obj[key],\n    (val, obj) => ({ ...obj, [key]: val })\n);\nconst nameLens = propLens(\"name\");\nconst user = { name: \"Alice\", age: 30 };\nnameLens.set(\"Bob\", user);  \u002F\u002F { name: \"Bob\", age: 30 } (new object, original unchanged)\n",[30,1859,1860,1865,1919,1967,1971,1984,1999,2012,2057,2061,2076,2080,2085,2114,2162,2166,2213,2231,2249,2265,2280,2284,2289,2315,2337,2347,2371,2375,2393,2411],{"__ignoreMap":28},[33,1861,1862],{"class":35,"line":36},[33,1863,1864],{"class":39},"\u002F\u002F ── Function composition (pipe and compose) ──\n",[33,1866,1867,1869,1872,1874,1876,1878,1881,1883,1885,1887,1890,1892,1894,1897,1900,1903,1906,1908,1910,1912,1914,1916],{"class":35,"line":43},[33,1868,84],{"class":83},[33,1870,1871],{"class":87}," pipe",[33,1873,91],{"class":83},[33,1875,95],{"class":94},[33,1877,379],{"class":83},[33,1879,1880],{"class":98},"fns",[33,1882,108],{"class":94},[33,1884,111],{"class":83},[33,1886,95],{"class":94},[33,1888,1889],{"class":98},"x",[33,1891,108],{"class":94},[33,1893,111],{"class":83},[33,1895,1896],{"class":94}," fns.",[33,1898,1899],{"class":87},"reduce",[33,1901,1902],{"class":94},"((",[33,1904,1905],{"class":98},"acc",[33,1907,102],{"class":94},[33,1909,1000],{"class":98},[33,1911,108],{"class":94},[33,1913,111],{"class":83},[33,1915,1031],{"class":87},[33,1917,1918],{"class":94},"(acc), x);\n",[33,1920,1921,1923,1926,1928,1930,1932,1934,1936,1938,1940,1942,1944,1946,1948,1951,1953,1955,1957,1959,1961,1963,1965],{"class":35,"line":49},[33,1922,84],{"class":83},[33,1924,1925],{"class":87}," compose",[33,1927,91],{"class":83},[33,1929,95],{"class":94},[33,1931,379],{"class":83},[33,1933,1880],{"class":98},[33,1935,108],{"class":94},[33,1937,111],{"class":83},[33,1939,95],{"class":94},[33,1941,1889],{"class":98},[33,1943,108],{"class":94},[33,1945,111],{"class":83},[33,1947,1896],{"class":94},[33,1949,1950],{"class":87},"reduceRight",[33,1952,1902],{"class":94},[33,1954,1905],{"class":98},[33,1956,102],{"class":94},[33,1958,1000],{"class":98},[33,1960,108],{"class":94},[33,1962,111],{"class":83},[33,1964,1031],{"class":87},[33,1966,1918],{"class":94},[33,1968,1969],{"class":35,"line":55},[33,1970,71],{"emptyLinePlaceholder":70},[33,1972,1973,1975,1978,1980,1982],{"class":35,"line":61},[33,1974,84],{"class":83},[33,1976,1977],{"class":132}," formatName",[33,1979,91],{"class":83},[33,1981,1871],{"class":87},[33,1983,1247],{"class":94},[33,1985,1986,1989,1991,1993,1996],{"class":35,"line":67},[33,1987,1988],{"class":98},"    name",[33,1990,1213],{"class":83},[33,1992,1231],{"class":94},[33,1994,1995],{"class":87},"trim",[33,1997,1998],{"class":94},"(),\n",[33,2000,2001,2003,2005,2007,2010],{"class":35,"line":74},[33,2002,1988],{"class":98},[33,2004,1213],{"class":83},[33,2006,1231],{"class":94},[33,2008,2009],{"class":87},"toLowerCase",[33,2011,1998],{"class":94},[33,2013,2014,2016,2018,2020,2023,2025,2028,2031,2034,2036,2039,2041,2044,2046,2049,2051,2054],{"class":35,"line":80},[33,2015,1988],{"class":98},[33,2017,1213],{"class":83},[33,2019,1231],{"class":94},[33,2021,2022],{"class":87},"replace",[33,2024,129],{"class":94},[33,2026,2027],{"class":177},"\u002F",[33,2029,2030],{"class":83},"\\b",[33,2032,2033],{"class":132},"\\w",[33,2035,2027],{"class":177},[33,2037,2038],{"class":83},"g",[33,2040,102],{"class":94},[33,2042,2043],{"class":98},"c",[33,2045,1213],{"class":83},[33,2047,2048],{"class":94}," c.",[33,2050,1234],{"class":87},[33,2052,2053],{"class":94},"()),  ",[33,2055,2056],{"class":39},"\u002F\u002F title case\n",[33,2058,2059],{"class":35,"line":123},[33,2060,761],{"class":94},[33,2062,2063,2066,2068,2071,2073],{"class":35,"line":147},[33,2064,2065],{"class":87},"formatName",[33,2067,129],{"class":94},[33,2069,2070],{"class":177},"\"  aLICE jones  \"",[33,2072,141],{"class":94},[33,2074,2075],{"class":39},"\u002F\u002F \"Alice Jones\"\n",[33,2077,2078],{"class":35,"line":152},[33,2079,71],{"emptyLinePlaceholder":70},[33,2081,2082],{"class":35,"line":158},[33,2083,2084],{"class":39},"\u002F\u002F ── Currying for reusable partial functions ──\n",[33,2086,2087,2089,2092,2094,2096,2098,2100,2102,2104,2106,2109,2111],{"class":35,"line":189},[33,2088,84],{"class":83},[33,2090,2091],{"class":87}," curry",[33,2093,91],{"class":83},[33,2095,95],{"class":94},[33,2097,1000],{"class":98},[33,2099,108],{"class":94},[33,2101,111],{"class":83},[33,2103,95],{"class":94},[33,2105,379],{"class":83},[33,2107,2108],{"class":98},"args",[33,2110,108],{"class":94},[33,2112,2113],{"class":83},"=>\n",[33,2115,2116,2119,2122,2125,2128,2130,2132,2134,2136,2138,2141,2143,2145,2148,2151,2153,2155,2157,2159],{"class":35,"line":205},[33,2117,2118],{"class":94},"    args.",[33,2120,2121],{"class":132},"length",[33,2123,2124],{"class":83}," >=",[33,2126,2127],{"class":94}," fn.",[33,2129,2121],{"class":132},[33,2131,737],{"class":83},[33,2133,1031],{"class":87},[33,2135,129],{"class":94},[33,2137,379],{"class":83},[33,2139,2140],{"class":94},"args) ",[33,2142,753],{"class":83},[33,2144,2091],{"class":87},[33,2146,2147],{"class":94},"(fn.",[33,2149,2150],{"class":87},"bind",[33,2152,129],{"class":94},[33,2154,1449],{"class":132},[33,2156,102],{"class":94},[33,2158,379],{"class":83},[33,2160,2161],{"class":94},"args));\n",[33,2163,2164],{"class":35,"line":210},[33,2165,71],{"emptyLinePlaceholder":70},[33,2167,2168,2170,2173,2175,2177,2179,2182,2184,2187,2189,2191,2194,2196,2198,2201,2203,2206,2208,2210],{"class":35,"line":216},[33,2169,84],{"class":83},[33,2171,2172],{"class":132}," log",[33,2174,91],{"class":83},[33,2176,2091],{"class":87},[33,2178,1902],{"class":94},[33,2180,2181],{"class":98},"level",[33,2183,102],{"class":94},[33,2185,2186],{"class":98},"message",[33,2188,108],{"class":94},[33,2190,111],{"class":83},[33,2192,2193],{"class":94}," console.",[33,2195,1296],{"class":87},[33,2197,129],{"class":94},[33,2199,2200],{"class":177},"`[${",[33,2202,2181],{"class":94},[33,2204,2205],{"class":177},"}] ${",[33,2207,2186],{"class":94},[33,2209,256],{"class":177},[33,2211,2212],{"class":94},"));\n",[33,2214,2215,2217,2220,2222,2224,2226,2229],{"class":35,"line":261},[33,2216,84],{"class":83},[33,2218,2219],{"class":132}," info",[33,2221,91],{"class":83},[33,2223,2172],{"class":87},[33,2225,129],{"class":94},[33,2227,2228],{"class":177},"\"INFO\"",[33,2230,761],{"class":94},[33,2232,2233,2235,2238,2240,2242,2244,2247],{"class":35,"line":267},[33,2234,84],{"class":83},[33,2236,2237],{"class":132}," error",[33,2239,91],{"class":83},[33,2241,2172],{"class":87},[33,2243,129],{"class":94},[33,2245,2246],{"class":177},"\"ERROR\"",[33,2248,761],{"class":94},[33,2250,2251,2254,2256,2259,2262],{"class":35,"line":272},[33,2252,2253],{"class":87},"info",[33,2255,129],{"class":94},[33,2257,2258],{"class":177},"\"started\"",[33,2260,2261],{"class":94},");   ",[33,2263,2264],{"class":39},"\u002F\u002F [INFO] started\n",[33,2266,2267,2270,2272,2275,2277],{"class":35,"line":278},[33,2268,2269],{"class":87},"error",[33,2271,129],{"class":94},[33,2273,2274],{"class":177},"\"crashed\"",[33,2276,141],{"class":94},[33,2278,2279],{"class":39},"\u002F\u002F [ERROR] crashed\n",[33,2281,2282],{"class":35,"line":317},[33,2283,71],{"emptyLinePlaceholder":70},[33,2285,2286],{"class":35,"line":343},[33,2287,2288],{"class":39},"\u002F\u002F ── Lens pattern for immutable deep updates ──\n",[33,2290,2291,2293,2296,2298,2300,2303,2305,2308,2310,2312],{"class":35,"line":348},[33,2292,84],{"class":83},[33,2294,2295],{"class":87}," lens",[33,2297,91],{"class":83},[33,2299,95],{"class":94},[33,2301,2302],{"class":98},"get",[33,2304,102],{"class":94},[33,2306,2307],{"class":98},"set",[33,2309,108],{"class":94},[33,2311,111],{"class":83},[33,2313,2314],{"class":94}," ({ get, set });\n",[33,2316,2317,2319,2322,2324,2326,2329,2331,2333,2335],{"class":35,"line":354},[33,2318,84],{"class":83},[33,2320,2321],{"class":87}," propLens",[33,2323,91],{"class":83},[33,2325,95],{"class":94},[33,2327,2328],{"class":98},"key",[33,2330,108],{"class":94},[33,2332,111],{"class":83},[33,2334,2295],{"class":87},[33,2336,1247],{"class":94},[33,2338,2339,2342,2344],{"class":35,"line":385},[33,2340,2341],{"class":98},"    obj",[33,2343,1213],{"class":83},[33,2345,2346],{"class":94}," obj[key],\n",[33,2348,2349,2352,2355,2357,2359,2361,2363,2366,2368],{"class":35,"line":408},[33,2350,2351],{"class":94},"    (",[33,2353,2354],{"class":98},"val",[33,2356,102],{"class":94},[33,2358,1210],{"class":98},[33,2360,108],{"class":94},[33,2362,111],{"class":83},[33,2364,2365],{"class":94}," ({ ",[33,2367,379],{"class":83},[33,2369,2370],{"class":94},"obj, [key]: val })\n",[33,2372,2373],{"class":35,"line":413},[33,2374,761],{"class":94},[33,2376,2377,2379,2382,2384,2386,2388,2391],{"class":35,"line":419},[33,2378,84],{"class":83},[33,2380,2381],{"class":132}," nameLens",[33,2383,91],{"class":83},[33,2385,2321],{"class":87},[33,2387,129],{"class":94},[33,2389,2390],{"class":177},"\"name\"",[33,2392,761],{"class":94},[33,2394,2395,2397,2399,2401,2403,2405,2407,2409],{"class":35,"line":424},[33,2396,84],{"class":83},[33,2398,477],{"class":132},[33,2400,91],{"class":83},[33,2402,482],{"class":94},[33,2404,197],{"class":177},[33,2406,487],{"class":94},[33,2408,490],{"class":132},[33,2410,493],{"class":94},[33,2412,2413,2416,2418,2420,2422,2425],{"class":35,"line":430},[33,2414,2415],{"class":94},"nameLens.",[33,2417,2307],{"class":87},[33,2419,129],{"class":94},[33,2421,598],{"class":177},[33,2423,2424],{"class":94},", user);  ",[33,2426,2427],{"class":39},"\u002F\u002F { name: \"Bob\", age: 30 } (new object, original unchanged)\n",[15,2429,2431],{"id":2430},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[20,2433,2434],{"language":22},[24,2435,2437],{"className":26,"code":2436,"language":22,"meta":28,"style":28},"\u002F\u002F ── Immutability has a performance cost (copying) ──\n\u002F\u002F For large data structures, deep copies are expensive.\n\u002F\u002F Use structural sharing (like Immer) for efficient immutable updates.\n\n\u002F\u002F ── Object.freeze is shallow ──\nconst frozen = Object.freeze({ nested: { value: 1 } });\nfrozen.nested.value = 2;  \u002F\u002F works! (nested is not frozen)\n\u002F\u002F Use deepFreeze (recursive) or Immer for deep immutability.\n\n\u002F\u002F ── `const` doesn't make objects immutable ──\nconst obj = { x: 1 };\nobj.x = 2;  \u002F\u002F ✓ works (const prevents reassignment, not mutation)\n\u002F\u002F obj = { x: 3 };  \u002F\u002F ✗ TypeError (can't reassign const)\n\n\u002F\u002F ── Arrow functions can't be used for everything in FP ──\n\u002F\u002F Arrow functions are great for pure functions (short, no `this`).\n\u002F\u002F But they can't be constructors, don't have `arguments`, and can't be generators.\n\n\u002F\u002F ── Functional doesn't mean \"no mutation ever\" ──\n\u002F\u002F Performance-critical code may need mutation (e.g., game loops, data processing).\n\u002F\u002F Use immutability at the architectural level (state management), mutation in hot paths.\n",[30,2438,2439,2444,2449,2454,2458,2463,2482,2498,2503,2507,2512,2528,2542,2550,2554,2559,2564,2569,2573,2578,2583],{"__ignoreMap":28},[33,2440,2441],{"class":35,"line":36},[33,2442,2443],{"class":39},"\u002F\u002F ── Immutability has a performance cost (copying) ──\n",[33,2445,2446],{"class":35,"line":43},[33,2447,2448],{"class":39},"\u002F\u002F For large data structures, deep copies are expensive.\n",[33,2450,2451],{"class":35,"line":49},[33,2452,2453],{"class":39},"\u002F\u002F Use structural sharing (like Immer) for efficient immutable updates.\n",[33,2455,2456],{"class":35,"line":55},[33,2457,71],{"emptyLinePlaceholder":70},[33,2459,2460],{"class":35,"line":61},[33,2461,2462],{"class":39},"\u002F\u002F ── Object.freeze is shallow ──\n",[33,2464,2465,2467,2469,2471,2473,2475,2478,2480],{"class":35,"line":67},[33,2466,84],{"class":83},[33,2468,782],{"class":132},[33,2470,91],{"class":83},[33,2472,787],{"class":94},[33,2474,790],{"class":87},[33,2476,2477],{"class":94},"({ nested: { value: ",[33,2479,133],{"class":132},[33,2481,804],{"class":94},[33,2483,2484,2487,2490,2492,2495],{"class":35,"line":74},[33,2485,2486],{"class":94},"frozen.nested.value ",[33,2488,2489],{"class":83},"=",[33,2491,734],{"class":132},[33,2493,2494],{"class":94},";  ",[33,2496,2497],{"class":39},"\u002F\u002F works! (nested is not frozen)\n",[33,2499,2500],{"class":35,"line":80},[33,2501,2502],{"class":39},"\u002F\u002F Use deepFreeze (recursive) or Immer for deep immutability.\n",[33,2504,2505],{"class":35,"line":123},[33,2506,71],{"emptyLinePlaceholder":70},[33,2508,2509],{"class":35,"line":147},[33,2510,2511],{"class":39},"\u002F\u002F ── `const` doesn't make objects immutable ──\n",[33,2513,2514,2516,2519,2521,2524,2526],{"class":35,"line":152},[33,2515,84],{"class":83},[33,2517,2518],{"class":132}," obj",[33,2520,91],{"class":83},[33,2522,2523],{"class":94}," { x: ",[33,2525,133],{"class":132},[33,2527,493],{"class":94},[33,2529,2530,2533,2535,2537,2539],{"class":35,"line":158},[33,2531,2532],{"class":94},"obj.x ",[33,2534,2489],{"class":83},[33,2536,734],{"class":132},[33,2538,2494],{"class":94},[33,2540,2541],{"class":39},"\u002F\u002F ✓ works (const prevents reassignment, not mutation)\n",[33,2543,2544,2547],{"class":35,"line":189},[33,2545,2546],{"class":39},"\u002F\u002F obj = { x: 3 };",[33,2548,2549],{"class":39},"  \u002F\u002F ✗ TypeError (can't reassign const)\n",[33,2551,2552],{"class":35,"line":205},[33,2553,71],{"emptyLinePlaceholder":70},[33,2555,2556],{"class":35,"line":210},[33,2557,2558],{"class":39},"\u002F\u002F ── Arrow functions can't be used for everything in FP ──\n",[33,2560,2561],{"class":35,"line":216},[33,2562,2563],{"class":39},"\u002F\u002F Arrow functions are great for pure functions (short, no `this`).\n",[33,2565,2566],{"class":35,"line":261},[33,2567,2568],{"class":39},"\u002F\u002F But they can't be constructors, don't have `arguments`, and can't be generators.\n",[33,2570,2571],{"class":35,"line":267},[33,2572,71],{"emptyLinePlaceholder":70},[33,2574,2575],{"class":35,"line":272},[33,2576,2577],{"class":39},"\u002F\u002F ── Functional doesn't mean \"no mutation ever\" ──\n",[33,2579,2580],{"class":35,"line":278},[33,2581,2582],{"class":39},"\u002F\u002F Performance-critical code may need mutation (e.g., game loops, data processing).\n",[33,2584,2585],{"class":35,"line":317},[33,2586,2587],{"class":39},"\u002F\u002F Use immutability at the architectural level (state management), mutation in hot paths.\n",[15,2589,2591],{"id":2590},"quick-quiz","🧠 Quick Quiz",[2593,2594,2595],"p",{},"Is this function pure? Why or why not?",[20,2597,2598],{"language":22},[24,2599,2601],{"className":26,"code":2600,"language":22,"meta":28,"style":28},"let counter = 0;\nconst getId = () => ++counter;\n",[30,2602,2603,2618],{"__ignoreMap":28},[33,2604,2605,2608,2611,2613,2616],{"class":35,"line":36},[33,2606,2607],{"class":83},"let",[33,2609,2610],{"class":94}," counter ",[33,2612,2489],{"class":83},[33,2614,2615],{"class":132}," 0",[33,2617,186],{"class":94},[33,2619,2620,2622,2625,2627,2630,2632,2635],{"class":35,"line":43},[33,2621,84],{"class":83},[33,2623,2624],{"class":87}," getId",[33,2626,91],{"class":83},[33,2628,2629],{"class":94}," () ",[33,2631,111],{"class":83},[33,2633,2634],{"class":83}," ++",[33,2636,2637],{"class":94},"counter;\n",[2639,2640,2641,2645,2652,2672,2675,2709,2712,2779],"details",{},[2642,2643,2644],"summary",{},"Answer",[2593,2646,2647,2651],{},[2648,2649,2650],"strong",{},"No, it's impure"," for two reasons:",[2653,2654,2655,2666],"ol",{},[2656,2657,2658,2661,2662,2665],"li",{},[2648,2659,2660],{},"Side effect",": it mutates the external variable ",[30,2663,2664],{},"counter"," (modifies shared state).",[2656,2667,2668,2671],{},[2648,2669,2670],{},"Non-deterministic",": each call returns a different value (1, 2, 3, ...) — the same \"input\" (no arguments) produces different outputs each time.",[2593,2673,2674],{},"A pure version would take the counter as an argument and return the new value:",[24,2676,2678],{"className":26,"code":2677,"language":22,"meta":28,"style":28},"const nextId = (counter) => counter + 1;  \u002F\u002F pure — same input → same output\n",[30,2679,2680],{"__ignoreMap":28},[33,2681,2682,2684,2687,2689,2691,2693,2695,2697,2699,2701,2704,2706],{"class":35,"line":36},[33,2683,84],{"class":83},[33,2685,2686],{"class":87}," nextId",[33,2688,91],{"class":83},[33,2690,95],{"class":94},[33,2692,2664],{"class":98},[33,2694,108],{"class":94},[33,2696,111],{"class":83},[33,2698,2610],{"class":94},[33,2700,117],{"class":83},[33,2702,2703],{"class":132}," 1",[33,2705,2494],{"class":94},[33,2707,2708],{"class":39},"\u002F\u002F pure — same input → same output\n",[2593,2710,2711],{},"Or use a closure with explicit state management (accepting that it's impure by design for IDs):",[24,2713,2715],{"className":26,"code":2714,"language":22,"meta":28,"style":28},"const createIdGenerator = () => {\n    let counter = 0;\n    return () => ++counter;  \u002F\u002F impure, but encapsulated (state is private)\n};\nconst getId = createIdGenerator();\n",[30,2716,2717,2732,2745,2762,2766],{"__ignoreMap":28},[33,2718,2719,2721,2724,2726,2728,2730],{"class":35,"line":36},[33,2720,84],{"class":83},[33,2722,2723],{"class":87}," createIdGenerator",[33,2725,91],{"class":83},[33,2727,2629],{"class":94},[33,2729,111],{"class":83},[33,2731,572],{"class":94},[33,2733,2734,2737,2739,2741,2743],{"class":35,"line":43},[33,2735,2736],{"class":83},"    let",[33,2738,2610],{"class":94},[33,2740,2489],{"class":83},[33,2742,2615],{"class":132},[33,2744,186],{"class":94},[33,2746,2747,2750,2752,2754,2756,2759],{"class":35,"line":49},[33,2748,2749],{"class":83},"    return",[33,2751,2629],{"class":94},[33,2753,111],{"class":83},[33,2755,2634],{"class":83},[33,2757,2758],{"class":94},"counter;  ",[33,2760,2761],{"class":39},"\u002F\u002F impure, but encapsulated (state is private)\n",[33,2763,2764],{"class":35,"line":55},[33,2765,606],{"class":94},[33,2767,2768,2770,2772,2774,2776],{"class":35,"line":61},[33,2769,84],{"class":83},[33,2771,2624],{"class":132},[33,2773,91],{"class":83},[33,2775,2723],{"class":87},[33,2777,2778],{"class":94},"();\n",[2593,2780,2781,2784],{},[2648,2782,2783],{},"The lesson",": a pure function's output depends only on its inputs and has no side effects. Functions that mutate external state or return different values on repeated calls with the same arguments are impure.",[2786,2787,2788],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}",{"title":28,"searchDepth":43,"depth":43,"links":2790},[2791,2792,2793,2794,2795,2796,2797],{"id":17,"depth":43,"text":18},{"id":448,"depth":43,"text":449},{"id":825,"depth":43,"text":826},{"id":1403,"depth":43,"text":1404},{"id":1851,"depth":43,"text":1852},{"id":2430,"depth":43,"text":2431},{"id":2590,"depth":43,"text":2591},"Deep-dive into functional programming in JavaScript: pure functions and referential transparency, immutability patterns, functor\u002Fmonad laws, the Either monad for error handling, and transducers for efficient data pipelines. Code-first reference for senior engineers.","md",{},"\u002Fjs\u002F23-functional-programming",{"title":5,"description":2798},"js\u002F23-functional-programming","eyxGdBnJ1BOQDxX7ZhNnU3ZzYxd5gfrkR1CQ4gmKPv8",1789924649511]