@k2works/claude-code-booster 3.6.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +42 -42
- package/bin/claude-code-booster +90 -90
- package/lib/assets/.claude/README.md +258 -239
- package/lib/assets/.claude/agent-memory/xp-programmer/MEMORY.md +6 -0
- package/lib/assets/.claude/agent-memory/xp-programmer/project_cargo_tracker.md +11 -0
- package/lib/assets/.claude/agent-memory/xp-programmer/project_ddd_patterns.md +27 -0
- package/lib/assets/.claude/agent-memory/xp-programmer/project_us07_route_assignment.md +19 -0
- package/lib/assets/.claude/scripts/generate-inception-deck.mjs +911 -911
- package/lib/assets/.claude/settings.json +11 -11
- package/lib/assets/.claude/skills/ai-agent-guidelines/SKILL.md +111 -111
- package/lib/assets/.claude/skills/analyzing-architecture/SKILL.md +83 -83
- package/lib/assets/.claude/skills/analyzing-business/SKILL.md +95 -95
- package/lib/assets/.claude/skills/analyzing-data-model/SKILL.md +77 -77
- package/lib/assets/.claude/skills/analyzing-domain-model/SKILL.md +117 -117
- package/lib/assets/.claude/skills/analyzing-inception-deck/SKILL.md +84 -84
- package/lib/assets/.claude/skills/analyzing-non-functional/SKILL.md +95 -95
- package/lib/assets/.claude/skills/analyzing-operation/SKILL.md +95 -95
- package/lib/assets/.claude/skills/analyzing-requirements/SKILL.md +91 -91
- package/lib/assets/.claude/skills/analyzing-tech-stack/SKILL.md +101 -101
- package/lib/assets/.claude/skills/analyzing-test-strategy/SKILL.md +89 -89
- package/lib/assets/.claude/skills/analyzing-ui-design/SKILL.md +80 -80
- package/lib/assets/.claude/skills/analyzing-usecases/SKILL.md +72 -72
- package/lib/assets/.claude/skills/creating-adr/SKILL.md +113 -113
- package/lib/assets/.claude/skills/developing-backend/SKILL.md +100 -100
- package/lib/assets/.claude/skills/developing-frontend/SKILL.md +93 -93
- package/lib/assets/.claude/skills/developing-release/SKILL.md +120 -120
- package/lib/assets/.claude/skills/generating-bmc/SKILL.md +97 -0
- package/lib/assets/.claude/skills/generating-slides/SKILL.md +94 -94
- package/lib/assets/.claude/skills/git-commit/SKILL.md +81 -81
- package/lib/assets/.claude/skills/killing-processes/SKILL.md +44 -44
- package/lib/assets/.claude/skills/operating-backup/SKILL.md +59 -59
- package/lib/assets/.claude/skills/operating-cicd/SKILL.md +54 -54
- package/lib/assets/.claude/skills/operating-deploy/SKILL.md +67 -67
- package/lib/assets/.claude/skills/operating-docs/SKILL.md +219 -219
- package/lib/assets/.claude/skills/operating-provision/SKILL.md +77 -77
- package/lib/assets/.claude/skills/operating-setup/SKILL.md +63 -63
- package/lib/assets/.claude/skills/orchestrating-analysis/SKILL.md +104 -104
- package/lib/assets/.claude/skills/orchestrating-development/SKILL.md +162 -162
- package/lib/assets/.claude/skills/orchestrating-operation/SKILL.md +158 -158
- package/lib/assets/.claude/skills/orchestrating-project/SKILL.md +144 -144
- package/lib/assets/.claude/skills/planning-releases/SKILL.md +119 -119
- package/lib/assets/.claude/skills/syncing-github-project/SKILL.md +151 -151
- package/lib/assets/.claude/skills/tracking-progress/SKILL.md +91 -91
- package/lib/assets/.claude/skills/validating-iteration-plan/SKILL.md +215 -215
- package/lib/assets/.devcontainer/devcontainer.json +34 -34
- package/lib/assets/.env.example +17 -17
- package/lib/assets/.gitattributes +4 -4
- package/lib/assets/.github/workflows/docker-publish.yml +77 -77
- package/lib/assets/.github/workflows/mkdocs.yml +39 -39
- package/lib/assets/AGENTS.md +94 -94
- package/lib/assets/CLAUDE.md +1 -0
- package/lib/assets/README.md +254 -254
- package/lib/assets/docker-compose.yml +33 -33
- package/lib/assets/docs/adr/index.md +10 -10
- package/lib/assets/docs/article/functional-desgin-ppp/all/01-immutability-and-data-transformation.md +475 -475
- package/lib/assets/docs/article/functional-desgin-ppp/all/02-function-composition.md +519 -519
- package/lib/assets/docs/article/functional-desgin-ppp/all/03-polymorphism.md +537 -537
- package/lib/assets/docs/article/functional-desgin-ppp/all/04-data-validation.md +300 -300
- package/lib/assets/docs/article/functional-desgin-ppp/all/05-property-based-testing.md +320 -320
- package/lib/assets/docs/article/functional-desgin-ppp/all/06-tdd-and-functional.md +498 -498
- package/lib/assets/docs/article/functional-desgin-ppp/all/07-composite-pattern.md +298 -298
- package/lib/assets/docs/article/functional-desgin-ppp/all/08-decorator-pattern.md +291 -291
- package/lib/assets/docs/article/functional-desgin-ppp/all/09-adapter-pattern.md +336 -336
- package/lib/assets/docs/article/functional-desgin-ppp/all/10-strategy-pattern.md +303 -303
- package/lib/assets/docs/article/functional-desgin-ppp/all/11-command-pattern.md +286 -286
- package/lib/assets/docs/article/functional-desgin-ppp/all/12-visitor-pattern.md +322 -322
- package/lib/assets/docs/article/functional-desgin-ppp/all/13-abstract-factory-pattern.md +319 -319
- package/lib/assets/docs/article/functional-desgin-ppp/all/14-abstract-server-pattern.md +365 -365
- package/lib/assets/docs/article/functional-desgin-ppp/all/15-gossiping-bus-drivers.md +156 -156
- package/lib/assets/docs/article/functional-desgin-ppp/all/16-payroll-system.md +178 -178
- package/lib/assets/docs/article/functional-desgin-ppp/all/17-video-rental-system.md +312 -312
- package/lib/assets/docs/article/functional-desgin-ppp/all/18-concurrency-system.md +287 -287
- package/lib/assets/docs/article/functional-desgin-ppp/all/19-wa-tor-simulation.md +286 -286
- package/lib/assets/docs/article/functional-desgin-ppp/all/20-pattern-interactions.md +274 -274
- package/lib/assets/docs/article/functional-desgin-ppp/all/21-best-practices.md +294 -294
- package/lib/assets/docs/article/functional-desgin-ppp/all/22-oo-to-fp-migration.md +337 -337
- package/lib/assets/docs/article/functional-desgin-ppp/all/index.md +388 -388
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/01-immutability-and-data-transformation.md +273 -273
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/02-function-composition.md +380 -380
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/03-polymorphism.md +384 -384
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/04-clojure-spec.md +350 -350
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/05-property-based-testing.md +352 -352
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/06-tdd-in-functional.md +383 -383
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/07-composite-pattern.md +529 -529
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/08-decorator-pattern.md +395 -395
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/09-adapter-pattern.md +399 -399
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/10-strategy-pattern.md +485 -485
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/11-command-pattern.md +566 -566
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/12-visitor-pattern.md +567 -567
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/13-abstract-factory-pattern.md +475 -475
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/14-abstract-server-pattern.md +462 -462
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/15-gossiping-bus-drivers.md +325 -325
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/16-payroll-system.md +401 -401
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/17-video-rental-system.md +450 -450
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/18-concurrency-system.md +475 -475
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/19-wator-simulation.md +739 -739
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/20-pattern-interactions.md +567 -567
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/21-best-practices.md +518 -518
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/22-oo-to-fp-migration.md +532 -532
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/index.md +241 -241
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/01-immutability-and-data-transformation.md +383 -383
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/02-function-composition.md +374 -374
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/03-polymorphism.md +375 -375
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/04-data-validation.md +195 -195
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/05-property-based-testing.md +268 -268
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/06-tdd-and-fp.md +294 -294
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/07-effects-and-pure-functions.md +164 -164
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/08-error-handling-strategies.md +168 -168
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/09-io-and-external-systems.md +254 -254
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/10-concurrency-patterns.md +269 -269
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/11-command-pattern.md +148 -148
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/12-visitor-pattern.md +176 -176
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/13-abstract-factory-pattern.md +604 -604
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/14-abstract-server-pattern.md +729 -729
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/15-gossiping-bus-drivers.md +291 -291
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/16-payroll-system.md +420 -420
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/17-video-rental-system.md +319 -319
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/18-concurrency-system.md +466 -466
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/19-wator-simulation.md +523 -523
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/20-pattern-interactions.md +287 -287
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/21-best-practices.md +340 -340
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/22-oo-to-fp-migration.md +395 -395
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/index.md +248 -248
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/01-immutability-and-data-transformation.md +384 -384
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/02-function-composition.md +452 -452
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/03-polymorphism.md +495 -495
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/04-data-validation.md +416 -416
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/05-property-based-testing.md +382 -382
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/06-tdd-functional.md +687 -687
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/07-composite-pattern.md +442 -442
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/08-decorator-pattern.md +479 -479
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/09-adapter-pattern.md +479 -479
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/10-strategy-pattern.md +427 -427
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/11-command-pattern.md +428 -428
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/12-visitor-pattern.md +339 -339
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/13-abstract-factory-pattern.md +309 -309
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/14-abstract-server-pattern.md +596 -596
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/15-gossiping-bus-drivers.md +355 -355
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/16-payroll-system.md +350 -350
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/17-video-rental-system.md +414 -414
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/18-concurrency-system.md +367 -367
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/19-wator-simulation.md +403 -403
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/20-pattern-interactions.md +291 -291
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/21-best-practices.md +324 -324
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/22-oo-to-fp-migration.md +332 -332
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/index.md +274 -274
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/01-immutability-and-data-transformation.md +298 -298
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/02-function-composition.md +304 -304
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/03-polymorphism.md +362 -362
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/04-data-validation.md +257 -257
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/05-property-based-testing.md +254 -254
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/06-tdd-functional.md +283 -283
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/07-composite-pattern.md +395 -395
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/08-decorator-pattern.md +319 -319
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/09-adapter-pattern.md +382 -382
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/10-strategy-pattern.md +287 -287
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/11-command-pattern.md +303 -303
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/12-visitor-pattern.md +326 -326
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/13-abstract-factory-pattern.md +332 -332
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/14-abstract-server-pattern.md +379 -379
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/15-gossiping-bus-drivers.md +177 -177
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/16-payroll-system.md +219 -219
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/17-video-rental-system.md +244 -244
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/18-concurrency-system.md +363 -363
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/19-wator-simulation.md +438 -438
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/20-pattern-interactions.md +325 -325
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/21-best-practices.md +403 -403
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/22-oo-to-fp-migration.md +469 -469
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/index.md +174 -174
- package/lib/assets/docs/article/functional-desgin-ppp/index.md +90 -90
- package/lib/assets/docs/article/functional-desgin-ppp/rust/01-immutability-and-data-transformation.md +450 -450
- package/lib/assets/docs/article/functional-desgin-ppp/rust/02-function-composition.md +463 -463
- package/lib/assets/docs/article/functional-desgin-ppp/rust/03-polymorphism.md +425 -425
- package/lib/assets/docs/article/functional-desgin-ppp/rust/04-data-validation.md +273 -273
- package/lib/assets/docs/article/functional-desgin-ppp/rust/05-property-based-testing.md +247 -247
- package/lib/assets/docs/article/functional-desgin-ppp/rust/06-tdd-and-functional.md +841 -841
- package/lib/assets/docs/article/functional-desgin-ppp/rust/07-composite-pattern.md +384 -384
- package/lib/assets/docs/article/functional-desgin-ppp/rust/08-decorator-pattern.md +383 -383
- package/lib/assets/docs/article/functional-desgin-ppp/rust/09-adapter-pattern.md +339 -339
- package/lib/assets/docs/article/functional-desgin-ppp/rust/10-strategy-pattern.md +331 -331
- package/lib/assets/docs/article/functional-desgin-ppp/rust/11-command-pattern.md +356 -356
- package/lib/assets/docs/article/functional-desgin-ppp/rust/12-visitor-pattern.md +379 -379
- package/lib/assets/docs/article/functional-desgin-ppp/rust/13-abstract-factory-pattern.md +361 -361
- package/lib/assets/docs/article/functional-desgin-ppp/rust/14-abstract-server-pattern.md +392 -392
- package/lib/assets/docs/article/functional-desgin-ppp/rust/15-gossiping-bus-drivers.md +300 -300
- package/lib/assets/docs/article/functional-desgin-ppp/rust/16-payroll-system.md +297 -297
- package/lib/assets/docs/article/functional-desgin-ppp/rust/17-video-rental-system.md +304 -304
- package/lib/assets/docs/article/functional-desgin-ppp/rust/18-concurrency-system.md +315 -315
- package/lib/assets/docs/article/functional-desgin-ppp/rust/19-wator-simulation.md +311 -311
- package/lib/assets/docs/article/functional-desgin-ppp/rust/20-pattern-interactions.md +304 -304
- package/lib/assets/docs/article/functional-desgin-ppp/rust/21-best-practices.md +336 -336
- package/lib/assets/docs/article/functional-desgin-ppp/rust/22-oo-to-fp-migration.md +349 -349
- package/lib/assets/docs/article/functional-desgin-ppp/rust/index.md +243 -243
- package/lib/assets/docs/article/functional-desgin-ppp/scala/01-immutability-and-data-transformation.md +328 -328
- package/lib/assets/docs/article/functional-desgin-ppp/scala/02-function-composition.md +348 -348
- package/lib/assets/docs/article/functional-desgin-ppp/scala/03-polymorphism.md +357 -357
- package/lib/assets/docs/article/functional-desgin-ppp/scala/04-data-validation.md +364 -364
- package/lib/assets/docs/article/functional-desgin-ppp/scala/05-property-based-testing.md +515 -515
- package/lib/assets/docs/article/functional-desgin-ppp/scala/06-tdd-functional.md +557 -557
- package/lib/assets/docs/article/functional-desgin-ppp/scala/07-composite-pattern.md +363 -363
- package/lib/assets/docs/article/functional-desgin-ppp/scala/08-decorator-pattern.md +327 -327
- package/lib/assets/docs/article/functional-desgin-ppp/scala/09-adapter-pattern.md +517 -517
- package/lib/assets/docs/article/functional-desgin-ppp/scala/10-strategy-pattern.md +441 -441
- package/lib/assets/docs/article/functional-desgin-ppp/scala/11-command-pattern.md +407 -407
- package/lib/assets/docs/article/functional-desgin-ppp/scala/12-visitor-pattern.md +379 -379
- package/lib/assets/docs/article/functional-desgin-ppp/scala/13-abstract-factory-pattern.md +398 -398
- package/lib/assets/docs/article/functional-desgin-ppp/scala/14-abstract-server-pattern.md +476 -476
- package/lib/assets/docs/article/functional-desgin-ppp/scala/15-gossiping-bus-drivers.md +391 -391
- package/lib/assets/docs/article/functional-desgin-ppp/scala/16-payroll-system.md +342 -342
- package/lib/assets/docs/article/functional-desgin-ppp/scala/17-video-rental-system.md +324 -324
- package/lib/assets/docs/article/functional-desgin-ppp/scala/18-concurrency-system.md +730 -730
- package/lib/assets/docs/article/functional-desgin-ppp/scala/19-wator-simulation.md +624 -624
- package/lib/assets/docs/article/functional-desgin-ppp/scala/20-pattern-interactions.md +512 -512
- package/lib/assets/docs/article/functional-desgin-ppp/scala/21-best-practices.md +433 -433
- package/lib/assets/docs/article/functional-desgin-ppp/scala/22-oo-to-fp-migration.md +688 -688
- package/lib/assets/docs/article/functional-desgin-ppp/scala/index.md +243 -243
- package/lib/assets/docs/article/getting-start-tdd/clojure/01-todo-list-and-first-test.md +166 -166
- package/lib/assets/docs/article/getting-start-tdd/clojure/02-fake-it-and-triangulation.md +162 -162
- package/lib/assets/docs/article/getting-start-tdd/clojure/03-obvious-implementation-and-refactoring.md +135 -135
- package/lib/assets/docs/article/getting-start-tdd/clojure/04-version-control-and-conventional-commits.md +88 -88
- package/lib/assets/docs/article/getting-start-tdd/clojure/05-package-management-and-static-analysis.md +299 -299
- package/lib/assets/docs/article/getting-start-tdd/clojure/06-task-runner-and-ci-cd.md +241 -241
- package/lib/assets/docs/article/getting-start-tdd/clojure/07-protocols-and-records.md +131 -131
- package/lib/assets/docs/article/getting-start-tdd/clojure/08-multimethods-and-design-patterns.md +130 -130
- package/lib/assets/docs/article/getting-start-tdd/clojure/09-namespaces-and-module-design.md +127 -127
- package/lib/assets/docs/article/getting-start-tdd/clojure/10-higher-order-functions-and-composition.md +114 -114
- package/lib/assets/docs/article/getting-start-tdd/clojure/11-persistent-data-and-pipeline.md +138 -138
- package/lib/assets/docs/article/getting-start-tdd/clojure/12-error-handling-and-spec.md +161 -161
- package/lib/assets/docs/article/getting-start-tdd/clojure/index.md +65 -65
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter01.md +232 -232
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter02.md +244 -244
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter03.md +202 -202
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter04.md +92 -92
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter05.md +256 -256
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter06.md +195 -195
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter07.md +214 -214
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter08.md +249 -249
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter09.md +174 -174
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter10.md +166 -166
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter11.md +192 -192
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter12.md +211 -211
- package/lib/assets/docs/article/getting-start-tdd/csharp/index.md +83 -83
- package/lib/assets/docs/article/getting-start-tdd/elixir/01-todo-list-and-first-test.md +87 -87
- package/lib/assets/docs/article/getting-start-tdd/elixir/02-fake-it-and-triangulation.md +95 -95
- package/lib/assets/docs/article/getting-start-tdd/elixir/03-obvious-implementation-and-refactoring.md +109 -109
- package/lib/assets/docs/article/getting-start-tdd/elixir/04-version-control-and-conventional-commits.md +96 -96
- package/lib/assets/docs/article/getting-start-tdd/elixir/05-package-management-and-static-analysis.md +88 -88
- package/lib/assets/docs/article/getting-start-tdd/elixir/06-task-runner-and-ci-cd.md +71 -71
- package/lib/assets/docs/article/getting-start-tdd/elixir/07-structs-and-protocols.md +110 -110
- package/lib/assets/docs/article/getting-start-tdd/elixir/08-pattern-matching-and-guards.md +108 -108
- package/lib/assets/docs/article/getting-start-tdd/elixir/09-module-design-and-behaviours.md +104 -104
- package/lib/assets/docs/article/getting-start-tdd/elixir/10-higher-order-functions-and-pipeline.md +178 -178
- package/lib/assets/docs/article/getting-start-tdd/elixir/11-stream-and-lazy-evaluation.md +142 -142
- package/lib/assets/docs/article/getting-start-tdd/elixir/12-error-handling-and-with.md +145 -145
- package/lib/assets/docs/article/getting-start-tdd/elixir/index.md +35 -35
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter01.md +202 -202
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter02.md +246 -246
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter03.md +218 -218
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter04.md +179 -179
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter05.md +267 -267
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter06.md +190 -190
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter07.md +161 -161
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter08.md +175 -175
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter09.md +222 -222
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter10.md +189 -189
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter11.md +212 -212
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter12.md +215 -215
- package/lib/assets/docs/article/getting-start-tdd/fsharp/index.md +71 -71
- package/lib/assets/docs/article/getting-start-tdd/go/01-todo-list-and-first-test.md +213 -213
- package/lib/assets/docs/article/getting-start-tdd/go/02-fake-it-and-triangulation.md +302 -302
- package/lib/assets/docs/article/getting-start-tdd/go/03-obvious-implementation-and-refactoring.md +339 -339
- package/lib/assets/docs/article/getting-start-tdd/go/04-version-control-and-conventional-commits.md +112 -112
- package/lib/assets/docs/article/getting-start-tdd/go/05-package-management-and-static-analysis.md +272 -272
- package/lib/assets/docs/article/getting-start-tdd/go/06-task-runner-and-ci-cd.md +233 -233
- package/lib/assets/docs/article/getting-start-tdd/go/07-encapsulation-and-polymorphism.md +394 -394
- package/lib/assets/docs/article/getting-start-tdd/go/08-design-patterns.md +422 -422
- package/lib/assets/docs/article/getting-start-tdd/go/09-solid-principles-and-module-design.md +400 -400
- package/lib/assets/docs/article/getting-start-tdd/go/10-higher-order-functions-and-composition.md +226 -226
- package/lib/assets/docs/article/getting-start-tdd/go/11-immutable-data-and-pipeline.md +296 -296
- package/lib/assets/docs/article/getting-start-tdd/go/12-error-handling-and-type-safety.md +411 -411
- package/lib/assets/docs/article/getting-start-tdd/go/index.md +83 -83
- package/lib/assets/docs/article/getting-start-tdd/haskell/01-todo-list-and-first-test.md +279 -279
- package/lib/assets/docs/article/getting-start-tdd/haskell/02-fake-it-and-triangulation.md +337 -337
- package/lib/assets/docs/article/getting-start-tdd/haskell/03-obvious-implementation-and-refactoring.md +257 -257
- package/lib/assets/docs/article/getting-start-tdd/haskell/04-version-control-and-conventional-commits.md +182 -182
- package/lib/assets/docs/article/getting-start-tdd/haskell/05-package-management-and-static-analysis.md +313 -313
- package/lib/assets/docs/article/getting-start-tdd/haskell/06-task-runner-and-ci-cd.md +309 -309
- package/lib/assets/docs/article/getting-start-tdd/haskell/07-algebraic-data-types-and-type-classes.md +412 -412
- package/lib/assets/docs/article/getting-start-tdd/haskell/08-pattern-matching-and-guards.md +390 -390
- package/lib/assets/docs/article/getting-start-tdd/haskell/09-module-design-and-smart-constructors.md +461 -461
- package/lib/assets/docs/article/getting-start-tdd/haskell/10-higher-order-functions-and-currying.md +434 -434
- package/lib/assets/docs/article/getting-start-tdd/haskell/11-function-composition-and-point-free.md +392 -392
- package/lib/assets/docs/article/getting-start-tdd/haskell/12-monad-and-error-handling.md +631 -631
- package/lib/assets/docs/article/getting-start-tdd/haskell/index.md +49 -49
- package/lib/assets/docs/article/getting-start-tdd/index.md +93 -93
- package/lib/assets/docs/article/getting-start-tdd/integration/01-language-overview.md +375 -375
- package/lib/assets/docs/article/getting-start-tdd/integration/02-test-framework-comparison.md +349 -349
- package/lib/assets/docs/article/getting-start-tdd/integration/03-tdd-pattern-comparison.md +445 -445
- package/lib/assets/docs/article/getting-start-tdd/integration/04-type-system-comparison.md +409 -409
- package/lib/assets/docs/article/getting-start-tdd/integration/05-dev-environment-comparison.md +330 -330
- package/lib/assets/docs/article/getting-start-tdd/integration/06-learning-roadmap.md +290 -290
- package/lib/assets/docs/article/getting-start-tdd/integration/index.md +69 -69
- package/lib/assets/docs/article/getting-start-tdd/java/01-todo-list-and-first-test.md +234 -234
- package/lib/assets/docs/article/getting-start-tdd/java/02-fake-it-and-triangulation.md +261 -261
- package/lib/assets/docs/article/getting-start-tdd/java/03-obvious-implementation-and-refactoring.md +185 -185
- package/lib/assets/docs/article/getting-start-tdd/java/04-version-control-and-conventional-commits.md +115 -115
- package/lib/assets/docs/article/getting-start-tdd/java/05-package-management-and-static-analysis.md +382 -382
- package/lib/assets/docs/article/getting-start-tdd/java/06-task-runner-and-ci-cd.md +272 -272
- package/lib/assets/docs/article/getting-start-tdd/java/07-encapsulation-and-polymorphism.md +626 -626
- package/lib/assets/docs/article/getting-start-tdd/java/08-design-patterns.md +393 -393
- package/lib/assets/docs/article/getting-start-tdd/java/09-solid-principles-and-module-design.md +310 -310
- package/lib/assets/docs/article/getting-start-tdd/java/10-higher-order-functions-and-composition.md +188 -188
- package/lib/assets/docs/article/getting-start-tdd/java/11-immutable-data-and-pipeline.md +167 -167
- package/lib/assets/docs/article/getting-start-tdd/java/12-error-handling-and-type-safety.md +205 -205
- package/lib/assets/docs/article/getting-start-tdd/java/index.md +61 -61
- package/lib/assets/docs/article/getting-start-tdd/node/01-todo-list-and-first-test.md +244 -244
- package/lib/assets/docs/article/getting-start-tdd/node/02-fake-it-and-triangulation.md +262 -262
- package/lib/assets/docs/article/getting-start-tdd/node/03-obvious-implementation-and-refactoring.md +169 -169
- package/lib/assets/docs/article/getting-start-tdd/node/04-version-control-and-conventional-commits.md +112 -112
- package/lib/assets/docs/article/getting-start-tdd/node/05-package-management-and-static-analysis.md +314 -314
- package/lib/assets/docs/article/getting-start-tdd/node/06-task-runner-and-ci-cd.md +235 -235
- package/lib/assets/docs/article/getting-start-tdd/node/07-encapsulation-and-polymorphism.md +327 -327
- package/lib/assets/docs/article/getting-start-tdd/node/08-design-patterns.md +322 -322
- package/lib/assets/docs/article/getting-start-tdd/node/09-solid-principles-and-module-design.md +285 -285
- package/lib/assets/docs/article/getting-start-tdd/node/10-higher-order-functions-and-composition.md +199 -199
- package/lib/assets/docs/article/getting-start-tdd/node/11-immutable-data-and-pipeline.md +207 -207
- package/lib/assets/docs/article/getting-start-tdd/node/12-error-handling-and-type-safety.md +295 -295
- package/lib/assets/docs/article/getting-start-tdd/node/index.md +56 -56
- package/lib/assets/docs/article/getting-start-tdd/php/01-todo-list-and-first-test.md +259 -259
- package/lib/assets/docs/article/getting-start-tdd/php/02-fake-it-and-triangulation.md +200 -200
- package/lib/assets/docs/article/getting-start-tdd/php/03-obvious-implementation-and-refactoring.md +248 -248
- package/lib/assets/docs/article/getting-start-tdd/php/04-version-control-and-conventional-commits.md +141 -141
- package/lib/assets/docs/article/getting-start-tdd/php/05-package-management-and-static-analysis.md +410 -410
- package/lib/assets/docs/article/getting-start-tdd/php/06-task-runner-and-ci-cd.md +321 -321
- package/lib/assets/docs/article/getting-start-tdd/php/07-encapsulation-and-polymorphism.md +372 -372
- package/lib/assets/docs/article/getting-start-tdd/php/08-design-patterns.md +453 -453
- package/lib/assets/docs/article/getting-start-tdd/php/09-solid-principles-and-module-design.md +460 -460
- package/lib/assets/docs/article/getting-start-tdd/php/10-higher-order-functions-and-composition.md +182 -182
- package/lib/assets/docs/article/getting-start-tdd/php/11-immutable-data-and-pipeline.md +266 -266
- package/lib/assets/docs/article/getting-start-tdd/php/12-error-handling-and-type-safety.md +308 -308
- package/lib/assets/docs/article/getting-start-tdd/php/index.md +84 -84
- package/lib/assets/docs/article/getting-start-tdd/python/01-todo-list-and-first-test.md +201 -201
- package/lib/assets/docs/article/getting-start-tdd/python/02-fake-it-and-triangulation.md +247 -247
- package/lib/assets/docs/article/getting-start-tdd/python/03-obvious-implementation-and-refactoring.md +199 -199
- package/lib/assets/docs/article/getting-start-tdd/python/04-version-control-and-conventional-commits.md +87 -87
- package/lib/assets/docs/article/getting-start-tdd/python/05-package-management-and-static-analysis.md +274 -274
- package/lib/assets/docs/article/getting-start-tdd/python/06-task-runner-and-ci-cd.md +190 -190
- package/lib/assets/docs/article/getting-start-tdd/python/07-encapsulation-and-polymorphism.md +208 -208
- package/lib/assets/docs/article/getting-start-tdd/python/08-design-patterns.md +172 -172
- package/lib/assets/docs/article/getting-start-tdd/python/09-solid-principles-and-module-design.md +130 -130
- package/lib/assets/docs/article/getting-start-tdd/python/10-higher-order-functions-and-composition.md +122 -122
- package/lib/assets/docs/article/getting-start-tdd/python/11-immutable-data-and-pipeline.md +116 -116
- package/lib/assets/docs/article/getting-start-tdd/python/12-error-handling-and-type-safety.md +126 -126
- package/lib/assets/docs/article/getting-start-tdd/python/index.md +55 -55
- package/lib/assets/docs/article/getting-start-tdd/ruby/01-todo-list-and-first-test.md +231 -231
- package/lib/assets/docs/article/getting-start-tdd/ruby/02-fake-it-and-triangulation.md +238 -238
- package/lib/assets/docs/article/getting-start-tdd/ruby/03-obvious-implementation-and-refactoring.md +228 -228
- package/lib/assets/docs/article/getting-start-tdd/ruby/04-version-control-and-conventional-commits.md +112 -112
- package/lib/assets/docs/article/getting-start-tdd/ruby/05-package-management-and-static-analysis.md +287 -287
- package/lib/assets/docs/article/getting-start-tdd/ruby/06-task-runner-and-ci-cd.md +248 -248
- package/lib/assets/docs/article/getting-start-tdd/ruby/07-encapsulation-and-polymorphism.md +279 -279
- package/lib/assets/docs/article/getting-start-tdd/ruby/08-design-patterns.md +329 -329
- package/lib/assets/docs/article/getting-start-tdd/ruby/09-solid-principles-and-module-design.md +196 -196
- package/lib/assets/docs/article/getting-start-tdd/ruby/10-higher-order-functions-and-composition.md +175 -175
- package/lib/assets/docs/article/getting-start-tdd/ruby/11-immutable-data-and-pipeline.md +237 -237
- package/lib/assets/docs/article/getting-start-tdd/ruby/12-error-handling-and-type-safety.md +398 -398
- package/lib/assets/docs/article/getting-start-tdd/ruby/index.md +83 -83
- package/lib/assets/docs/article/getting-start-tdd/rust/01-todo-list-and-first-test.md +211 -211
- package/lib/assets/docs/article/getting-start-tdd/rust/02-fake-it-and-triangulation.md +264 -264
- package/lib/assets/docs/article/getting-start-tdd/rust/03-obvious-implementation-and-refactoring.md +233 -233
- package/lib/assets/docs/article/getting-start-tdd/rust/04-version-control-and-conventional-commits.md +92 -92
- package/lib/assets/docs/article/getting-start-tdd/rust/05-package-management-and-static-analysis.md +212 -212
- package/lib/assets/docs/article/getting-start-tdd/rust/06-task-runner-and-ci-cd.md +164 -164
- package/lib/assets/docs/article/getting-start-tdd/rust/07-encapsulation-and-polymorphism.md +142 -142
- package/lib/assets/docs/article/getting-start-tdd/rust/08-design-patterns.md +145 -145
- package/lib/assets/docs/article/getting-start-tdd/rust/09-solid-principles-and-module-design.md +110 -110
- package/lib/assets/docs/article/getting-start-tdd/rust/10-higher-order-functions-and-composition.md +94 -94
- package/lib/assets/docs/article/getting-start-tdd/rust/11-immutable-data-and-pipeline.md +105 -105
- package/lib/assets/docs/article/getting-start-tdd/rust/12-error-handling-and-type-safety.md +112 -112
- package/lib/assets/docs/article/getting-start-tdd/rust/index.md +83 -83
- package/lib/assets/docs/article/getting-start-tdd/scala/01-todo-list-and-first-test.md +111 -111
- package/lib/assets/docs/article/getting-start-tdd/scala/02-fake-it-and-triangulation.md +107 -107
- package/lib/assets/docs/article/getting-start-tdd/scala/03-obvious-implementation-and-refactoring.md +99 -99
- package/lib/assets/docs/article/getting-start-tdd/scala/04-version-control-and-conventional-commits.md +123 -123
- package/lib/assets/docs/article/getting-start-tdd/scala/05-package-management-and-static-analysis.md +196 -196
- package/lib/assets/docs/article/getting-start-tdd/scala/06-task-runner-and-ci-cd.md +186 -186
- package/lib/assets/docs/article/getting-start-tdd/scala/07-case-classes-and-traits.md +139 -139
- package/lib/assets/docs/article/getting-start-tdd/scala/08-pattern-matching-and-sealed-traits.md +106 -106
- package/lib/assets/docs/article/getting-start-tdd/scala/09-packages-and-module-design.md +75 -75
- package/lib/assets/docs/article/getting-start-tdd/scala/10-higher-order-functions-and-composition.md +104 -104
- package/lib/assets/docs/article/getting-start-tdd/scala/11-collections-and-lazy-evaluation.md +94 -94
- package/lib/assets/docs/article/getting-start-tdd/scala/12-error-handling-and-type-safety.md +92 -92
- package/lib/assets/docs/article/getting-start-tdd/scala/index.md +65 -65
- package/lib/assets/docs/article/grokking-concurrency/all/index.md +404 -404
- package/lib/assets/docs/article/grokking-concurrency/all/part-1-ch02-sequential.md +554 -554
- package/lib/assets/docs/article/grokking-concurrency/all/part-2-ch04-05-threads.md +469 -469
- package/lib/assets/docs/article/grokking-concurrency/all/part-3-ch06-multitasking.md +520 -520
- package/lib/assets/docs/article/grokking-concurrency/all/part-4-ch07-parallel-patterns.md +420 -420
- package/lib/assets/docs/article/grokking-concurrency/all/part-5-ch08-09-synchronization.md +510 -510
- package/lib/assets/docs/article/grokking-concurrency/all/part-6-ch10-11-nonblocking-io.md +435 -435
- package/lib/assets/docs/article/grokking-concurrency/all/part-7-ch12-async.md +465 -465
- package/lib/assets/docs/article/grokking-concurrency/all/part-8-ch13-mapreduce.md +377 -377
- package/lib/assets/docs/article/grokking-concurrency/clojure/index.md +116 -116
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-1.md +108 -108
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-2.md +101 -101
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-3.md +122 -122
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-4.md +123 -123
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-5.md +118 -118
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-6.md +89 -89
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-7.md +100 -100
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-8.md +120 -120
- package/lib/assets/docs/article/grokking-concurrency/csharp/index.md +101 -101
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-1.md +97 -97
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-2.md +123 -123
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-3.md +101 -101
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-4.md +112 -112
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-5.md +99 -99
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-6.md +61 -61
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-7.md +84 -84
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-8.md +92 -92
- package/lib/assets/docs/article/grokking-concurrency/fsharp/index.md +65 -65
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-1.md +80 -80
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-2.md +103 -103
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-3.md +94 -94
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-4.md +110 -110
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-5.md +104 -104
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-6.md +93 -93
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-7.md +121 -121
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-8.md +107 -107
- package/lib/assets/docs/article/grokking-concurrency/haskell/index.md +248 -248
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-1.md +96 -96
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-2.md +96 -96
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-3.md +91 -91
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-4.md +106 -106
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-5.md +99 -99
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-6.md +95 -95
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-7.md +111 -111
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-8.md +118 -118
- package/lib/assets/docs/article/grokking-concurrency/index.md +66 -66
- package/lib/assets/docs/article/grokking-concurrency/java/index.md +102 -102
- package/lib/assets/docs/article/grokking-concurrency/java/part-1.md +308 -308
- package/lib/assets/docs/article/grokking-concurrency/java/part-2.md +334 -334
- package/lib/assets/docs/article/grokking-concurrency/java/part-3.md +221 -221
- package/lib/assets/docs/article/grokking-concurrency/java/part-4.md +213 -213
- package/lib/assets/docs/article/grokking-concurrency/java/part-5.md +112 -112
- package/lib/assets/docs/article/grokking-concurrency/java/part-6.md +69 -69
- package/lib/assets/docs/article/grokking-concurrency/java/part-7.md +101 -101
- package/lib/assets/docs/article/grokking-concurrency/java/part-8.md +101 -101
- package/lib/assets/docs/article/grokking-concurrency/python/index.md +313 -313
- package/lib/assets/docs/article/grokking-concurrency/python/part-1.md +239 -239
- package/lib/assets/docs/article/grokking-concurrency/python/part-2.md +418 -418
- package/lib/assets/docs/article/grokking-concurrency/python/part-3.md +227 -227
- package/lib/assets/docs/article/grokking-concurrency/python/part-4.md +299 -299
- package/lib/assets/docs/article/grokking-concurrency/python/part-5.md +315 -315
- package/lib/assets/docs/article/grokking-concurrency/python/part-6.md +297 -297
- package/lib/assets/docs/article/grokking-concurrency/python/part-7.md +314 -314
- package/lib/assets/docs/article/grokking-concurrency/python/part-8.md +360 -360
- package/lib/assets/docs/article/grokking-concurrency/rust/index.md +270 -270
- package/lib/assets/docs/article/grokking-concurrency/rust/part-1.md +108 -108
- package/lib/assets/docs/article/grokking-concurrency/rust/part-2.md +120 -120
- package/lib/assets/docs/article/grokking-concurrency/rust/part-3.md +126 -126
- package/lib/assets/docs/article/grokking-concurrency/rust/part-4.md +175 -175
- package/lib/assets/docs/article/grokking-concurrency/rust/part-5.md +158 -158
- package/lib/assets/docs/article/grokking-concurrency/rust/part-6.md +94 -94
- package/lib/assets/docs/article/grokking-concurrency/rust/part-7.md +133 -133
- package/lib/assets/docs/article/grokking-concurrency/rust/part-8.md +155 -155
- package/lib/assets/docs/article/grokking-concurrency/scala/index.md +69 -69
- package/lib/assets/docs/article/grokking-concurrency/scala/part-1.md +78 -78
- package/lib/assets/docs/article/grokking-concurrency/scala/part-2.md +112 -112
- package/lib/assets/docs/article/grokking-concurrency/scala/part-3.md +93 -93
- package/lib/assets/docs/article/grokking-concurrency/scala/part-4.md +110 -110
- package/lib/assets/docs/article/grokking-concurrency/scala/part-5.md +119 -119
- package/lib/assets/docs/article/grokking-concurrency/scala/part-6.md +83 -83
- package/lib/assets/docs/article/grokking-concurrency/scala/part-7.md +131 -131
- package/lib/assets/docs/article/grokking-concurrency/scala/part-8.md +129 -129
- package/lib/assets/docs/article/grokkingfp/all/index.md +368 -368
- package/lib/assets/docs/article/grokkingfp/all/part-1-ch01-fp-introduction.md +530 -530
- package/lib/assets/docs/article/grokkingfp/all/part-1-ch02-pure-functions.md +923 -923
- package/lib/assets/docs/article/grokkingfp/all/part-2-ch03-immutable-data.md +1128 -1128
- package/lib/assets/docs/article/grokkingfp/all/part-2-ch04-higher-order-functions.md +1104 -1104
- package/lib/assets/docs/article/grokkingfp/all/part-2-ch05-flatmap.md +1026 -1026
- package/lib/assets/docs/article/grokkingfp/all/part-3-ch06-option.md +785 -785
- package/lib/assets/docs/article/grokkingfp/all/part-3-ch07-either-adt.md +871 -871
- package/lib/assets/docs/article/grokkingfp/all/part-4-ch08-io-monad.md +972 -972
- package/lib/assets/docs/article/grokkingfp/all/part-4-ch09-streams.md +926 -926
- package/lib/assets/docs/article/grokkingfp/all/part-5-ch10-concurrency.md +870 -870
- package/lib/assets/docs/article/grokkingfp/all/part-6-ch11-application.md +715 -715
- package/lib/assets/docs/article/grokkingfp/all/part-6-ch12-testing.md +626 -626
- package/lib/assets/docs/article/grokkingfp/all/writing-plan.md +712 -712
- package/lib/assets/docs/article/grokkingfp/clojure/index.md +276 -276
- package/lib/assets/docs/article/grokkingfp/clojure/part-1.md +667 -667
- package/lib/assets/docs/article/grokkingfp/clojure/part-2.md +643 -643
- package/lib/assets/docs/article/grokkingfp/clojure/part-3.md +620 -620
- package/lib/assets/docs/article/grokkingfp/clojure/part-4.md +697 -697
- package/lib/assets/docs/article/grokkingfp/clojure/part-5.md +751 -751
- package/lib/assets/docs/article/grokkingfp/clojure/part-6.md +721 -721
- package/lib/assets/docs/article/grokkingfp/csharp/index.md +246 -246
- package/lib/assets/docs/article/grokkingfp/csharp/part-1.md +811 -811
- package/lib/assets/docs/article/grokkingfp/csharp/part-2.md +971 -971
- package/lib/assets/docs/article/grokkingfp/csharp/part-3.md +981 -981
- package/lib/assets/docs/article/grokkingfp/csharp/part-4.md +949 -949
- package/lib/assets/docs/article/grokkingfp/csharp/part-5.md +947 -947
- package/lib/assets/docs/article/grokkingfp/csharp/part-6.md +739 -739
- package/lib/assets/docs/article/grokkingfp/elixir/index.md +203 -203
- package/lib/assets/docs/article/grokkingfp/elixir/part-1.md +712 -712
- package/lib/assets/docs/article/grokkingfp/elixir/part-2.md +838 -838
- package/lib/assets/docs/article/grokkingfp/elixir/part-3.md +985 -985
- package/lib/assets/docs/article/grokkingfp/elixir/part-4.md +974 -974
- package/lib/assets/docs/article/grokkingfp/elixir/part-5.md +1286 -1286
- package/lib/assets/docs/article/grokkingfp/elixir/part-6.md +1049 -1049
- package/lib/assets/docs/article/grokkingfp/fsharp/index.md +210 -210
- package/lib/assets/docs/article/grokkingfp/fsharp/part-1.md +714 -714
- package/lib/assets/docs/article/grokkingfp/fsharp/part-2.md +961 -961
- package/lib/assets/docs/article/grokkingfp/fsharp/part-3.md +972 -972
- package/lib/assets/docs/article/grokkingfp/fsharp/part-4.md +832 -832
- package/lib/assets/docs/article/grokkingfp/fsharp/part-5.md +911 -911
- package/lib/assets/docs/article/grokkingfp/fsharp/part-6.md +922 -922
- package/lib/assets/docs/article/grokkingfp/haskell/index.md +234 -234
- package/lib/assets/docs/article/grokkingfp/haskell/part-1.md +591 -591
- package/lib/assets/docs/article/grokkingfp/haskell/part-2.md +866 -866
- package/lib/assets/docs/article/grokkingfp/haskell/part-3.md +915 -915
- package/lib/assets/docs/article/grokkingfp/haskell/part-4.md +878 -878
- package/lib/assets/docs/article/grokkingfp/haskell/part-5.md +845 -845
- package/lib/assets/docs/article/grokkingfp/haskell/part-6.md +844 -844
- package/lib/assets/docs/article/grokkingfp/index.md +143 -143
- package/lib/assets/docs/article/grokkingfp/java/index.md +211 -211
- package/lib/assets/docs/article/grokkingfp/java/part-1.md +648 -648
- package/lib/assets/docs/article/grokkingfp/java/part-2.md +675 -675
- package/lib/assets/docs/article/grokkingfp/java/part-3.md +672 -672
- package/lib/assets/docs/article/grokkingfp/java/part-4.md +771 -771
- package/lib/assets/docs/article/grokkingfp/java/part-5.md +959 -959
- package/lib/assets/docs/article/grokkingfp/java/part-6.md +1328 -1328
- package/lib/assets/docs/article/grokkingfp/python/index.md +258 -258
- package/lib/assets/docs/article/grokkingfp/python/part-1.md +443 -443
- package/lib/assets/docs/article/grokkingfp/python/part-2.md +958 -958
- package/lib/assets/docs/article/grokkingfp/python/part-3.md +1004 -1004
- package/lib/assets/docs/article/grokkingfp/python/part-4.md +765 -765
- package/lib/assets/docs/article/grokkingfp/python/part-5.md +747 -747
- package/lib/assets/docs/article/grokkingfp/python/part-6.md +861 -861
- package/lib/assets/docs/article/grokkingfp/ruby/index.md +330 -330
- package/lib/assets/docs/article/grokkingfp/ruby/part-1.md +755 -755
- package/lib/assets/docs/article/grokkingfp/ruby/part-2.md +938 -938
- package/lib/assets/docs/article/grokkingfp/ruby/part-3.md +946 -946
- package/lib/assets/docs/article/grokkingfp/ruby/part-4.md +921 -921
- package/lib/assets/docs/article/grokkingfp/ruby/part-5.md +908 -908
- package/lib/assets/docs/article/grokkingfp/ruby/part-6.md +1412 -1412
- package/lib/assets/docs/article/grokkingfp/rust/index.md +242 -242
- package/lib/assets/docs/article/grokkingfp/rust/part-1.md +634 -634
- package/lib/assets/docs/article/grokkingfp/rust/part-2.md +1060 -1060
- package/lib/assets/docs/article/grokkingfp/rust/part-3.md +994 -994
- package/lib/assets/docs/article/grokkingfp/rust/part-4.md +573 -573
- package/lib/assets/docs/article/grokkingfp/rust/part-5.md +705 -705
- package/lib/assets/docs/article/grokkingfp/rust/part-6.md +508 -508
- package/lib/assets/docs/article/grokkingfp/scala/index.md +171 -171
- package/lib/assets/docs/article/grokkingfp/scala/part-1.md +543 -543
- package/lib/assets/docs/article/grokkingfp/scala/part-2.md +946 -946
- package/lib/assets/docs/article/grokkingfp/scala/part-3.md +919 -919
- package/lib/assets/docs/article/grokkingfp/scala/part-4.md +742 -742
- package/lib/assets/docs/article/grokkingfp/scala/part-5.md +722 -722
- package/lib/assets/docs/article/grokkingfp/scala/part-6.md +867 -867
- package/lib/assets/docs/article/grokkingfp/typescript/index.md +273 -273
- package/lib/assets/docs/article/grokkingfp/typescript/part-1.md +561 -561
- package/lib/assets/docs/article/grokkingfp/typescript/part-2.md +1129 -1129
- package/lib/assets/docs/article/grokkingfp/typescript/part-3.md +842 -842
- package/lib/assets/docs/article/grokkingfp/typescript/part-4.md +1087 -1087
- package/lib/assets/docs/article/grokkingfp/typescript/part-5.md +717 -717
- package/lib/assets/docs/article/grokkingfp/typescript/part-6.md +982 -982
- package/lib/assets/docs/article/practical-database-design/index.md +121 -121
- package/lib/assets/docs/article/practical-database-design/part1/chapter01.md +288 -288
- package/lib/assets/docs/article/practical-database-design/part1/chapter02.md +518 -518
- package/lib/assets/docs/article/practical-database-design/part1/chapter03.md +557 -557
- package/lib/assets/docs/article/practical-database-design/part2/chapter04.md +924 -924
- package/lib/assets/docs/article/practical-database-design/part2/chapter05.md +1627 -1627
- package/lib/assets/docs/article/practical-database-design/part2/chapter06.md +2716 -2716
- package/lib/assets/docs/article/practical-database-design/part2/chapter07.md +2082 -2082
- package/lib/assets/docs/article/practical-database-design/part2/chapter08.md +2105 -2105
- package/lib/assets/docs/article/practical-database-design/part2/chapter09.md +2031 -2031
- package/lib/assets/docs/article/practical-database-design/part2/chapter10.md +1387 -1387
- package/lib/assets/docs/article/practical-database-design/part2/chapter11.md +1677 -1677
- package/lib/assets/docs/article/practical-database-design/part2/chapter12.md +1417 -1417
- package/lib/assets/docs/article/practical-database-design/part2/chapter13.md +1434 -1434
- package/lib/assets/docs/article/practical-database-design/part3/chapter14.md +667 -667
- package/lib/assets/docs/article/practical-database-design/part3/chapter15.md +1625 -1625
- package/lib/assets/docs/article/practical-database-design/part3/chapter16.md +1915 -1915
- package/lib/assets/docs/article/practical-database-design/part3/chapter17.md +1708 -1708
- package/lib/assets/docs/article/practical-database-design/part3/chapter18.md +2095 -2095
- package/lib/assets/docs/article/practical-database-design/part3/chapter19.md +1123 -1123
- package/lib/assets/docs/article/practical-database-design/part3/chapter20.md +1031 -1031
- package/lib/assets/docs/article/practical-database-design/part3/chapter21.md +1382 -1382
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter14-orm.md +991 -991
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter15-orm.md +1300 -1300
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter16-orm.md +1166 -1166
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter17-orm.md +1584 -1584
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter18-orm.md +1183 -1183
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter19-orm.md +1016 -1016
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter20-orm.md +1753 -1753
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter21-orm.md +1447 -1447
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter22-orm.md +1878 -1878
- package/lib/assets/docs/article/practical-database-design/part4/chapter22.md +965 -965
- package/lib/assets/docs/article/practical-database-design/part4/chapter23.md +2069 -2069
- package/lib/assets/docs/article/practical-database-design/part4/chapter24.md +2439 -2439
- package/lib/assets/docs/article/practical-database-design/part4/chapter25.md +3661 -3661
- package/lib/assets/docs/article/practical-database-design/part4/chapter26.md +2916 -2916
- package/lib/assets/docs/article/practical-database-design/part4/chapter27.md +3105 -3105
- package/lib/assets/docs/article/practical-database-design/part4/chapter28.md +2697 -2697
- package/lib/assets/docs/article/practical-database-design/part4/chapter29.md +2544 -2544
- package/lib/assets/docs/article/practical-database-design/part4/chapter30.md +2180 -2180
- package/lib/assets/docs/article/practical-database-design/part4/chapter31.md +1192 -1192
- package/lib/assets/docs/article/practical-database-design/part4/chapter32.md +2101 -2101
- package/lib/assets/docs/article/practical-database-design/part5/chapter33.md +1032 -1032
- package/lib/assets/docs/article/practical-database-design/part5/chapter34.md +1609 -1609
- package/lib/assets/docs/article/practical-database-design/part5/chapter35.md +1453 -1453
- package/lib/assets/docs/article/practical-database-design/part5/chapter36.md +1292 -1292
- package/lib/assets/docs/article/practical-database-design/part5/chapter37.md +1470 -1470
- package/lib/assets/docs/article/practical-database-design/part5/chapter38.md +1698 -1698
- package/lib/assets/docs/article/practical-database-design/part5/chapter39.md +2334 -2334
- package/lib/assets/docs/article/practical-database-design/study/study2-1.md +1693 -1693
- package/lib/assets/docs/article/practical-database-design/study/study2-2.md +1347 -1347
- package/lib/assets/docs/article/practical-database-design/study/study2-3.md +2044 -2044
- package/lib/assets/docs/article/practical-database-design/study/study2-4.md +2229 -2229
- package/lib/assets/docs/article/practical-database-design/study/study2-5.md +2418 -2418
- package/lib/assets/docs/article/practical-database-design/study/study3-1.md +2205 -2205
- package/lib/assets/docs/article/practical-database-design/study/study3-2.md +2221 -2221
- package/lib/assets/docs/article/practical-database-design/study/study3-3.md +2253 -2253
- package/lib/assets/docs/article/practical-database-design/study/study3-4.md +2106 -2106
- package/lib/assets/docs/article/practical-database-design/study/study3-5.md +2507 -2507
- package/lib/assets/docs/article/practical-database-design/study/study4-1.md +2587 -2587
- package/lib/assets/docs/article/practical-database-design/study/study4-2.md +2075 -2075
- package/lib/assets/docs/article/practical-database-design/study/study4-3.md +1805 -1805
- package/lib/assets/docs/article/practical-database-design/study/study4-4.md +1895 -1895
- package/lib/assets/docs/article/practical-database-design/study/study4-5.md +2878 -2878
- package/lib/assets/docs/assets/css/extra.css +29 -29
- package/lib/assets/docs/assets/js/extra.js +44 -44
- package/lib/assets/docs/development/index.md +39 -39
- package/lib/assets/docs/operation/index.md +11 -11
- package/lib/assets/docs/reference/CodexCLIMCP/343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/351/226/213/347/231/272/343/203/225/343/203/255/343/203/274.md +532 -532
- package/lib/assets/docs/reference/CodexCLIMCP/343/202/265/343/203/274/343/203/220/343/203/274/350/250/255/345/256/232/346/211/213/351/240/206.md +341 -341
- package/lib/assets/docs/reference/Java/343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/347/222/260/345/242/203/346/247/213/347/257/211/343/202/254/343/202/244/343/203/211.md +581 -581
- package/lib/assets/docs/reference/SonarQube/343/203/255/343/203/274/343/202/253/343/203/253/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +642 -642
- package/lib/assets/docs/reference/TypeScript/343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/347/222/260/345/242/203/346/247/213/347/257/211/343/202/254/343/202/244/343/203/211.md +465 -465
- package/lib/assets/docs/reference/UI/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +450 -450
- package/lib/assets/docs/reference/images/Ansoff.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/BrandBasicStrategy.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/BrandCategorization.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/BrandRecurutementStrategy.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/BrandValue.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/BusinessActivitiy.svg +3 -3
- package/lib/assets/docs/reference/images/HRM.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/MarketingStructure.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/OrganizationElemnts.svg +3 -3
- package/lib/assets/docs/reference/images/PPM.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/PositioningMap.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/ProductLayer.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/ProductMix.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/SWOT.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/TargetMarket.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/ThreeGenericStrategies.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/VRIO.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/ValueChain.drawio.svg +3 -3
- package/lib/assets/docs/reference/index.md +52 -52
- package/lib/assets/docs/reference//343/202/210/343/201/204/343/202/275/343/203/225/343/203/210/343/202/246/343/202/247/343/202/242/343/201/250/343/201/257.md +250 -250
- package/lib/assets/docs/reference//343/202/242/343/203/274/343/202/255/343/203/206/343/202/257/343/203/201/343/203/243/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +2216 -2216
- package/lib/assets/docs/reference//343/202/244/343/203/263/343/203/225/343/203/251/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +1878 -1878
- package/lib/assets/docs/reference//343/202/250/343/202/257/343/202/271/343/203/210/343/203/252/343/203/274/343/203/240/343/203/227/343/203/255/343/202/260/343/203/251/343/203/237/343/203/263/343/202/260.md +550 -550
- package/lib/assets/docs/reference//343/202/263/343/203/274/343/203/207/343/202/243/343/203/263/343/202/260/343/201/250/343/203/206/343/202/271/343/203/210/343/202/254/343/202/244/343/203/211.md +705 -705
- package/lib/assets/docs/reference//343/203/206/343/202/271/343/203/210/346/210/246/347/225/245/343/202/254/343/202/244/343/203/211.md +1313 -1313
- package/lib/assets/docs/reference//343/203/207/343/203/274/343/202/277/343/203/242/343/203/207/343/203/253/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +311 -311
- package/lib/assets/docs/reference//343/203/211/343/203/241/343/202/244/343/203/263/343/203/242/343/203/207/343/203/253/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +599 -599
- package/lib/assets/docs/reference//343/203/223/343/202/270/343/203/215/343/202/271/343/202/242/343/203/274/343/202/255/343/203/206/343/202/257/343/203/201/343/203/243/345/210/206/346/236/220/343/202/254/343/202/244/343/203/211.md +528 -528
- package/lib/assets/docs/reference//343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271/344/275/234/346/210/220/343/202/254/343/202/244/343/203/211.md +689 -689
- package/lib/assets/docs/reference//343/203/252/343/203/252/343/203/274/343/202/271/343/202/254/343/202/244/343/203/211.md +461 -461
- package/lib/assets/docs/reference//343/203/252/343/203/252/343/203/274/343/202/271/343/203/273/343/202/244/343/203/206/343/203/254/343/203/274/343/202/267/343/203/247/343/203/263/350/250/210/347/224/273/343/202/254/343/202/244/343/203/211.md +580 -580
- package/lib/assets/docs/reference//343/203/255/343/202/270/343/202/253/343/203/253/343/202/267/343/203/263/343/202/255/343/203/263/343/202/260.md +1367 -1367
- package/lib/assets/docs/reference//344/274/201/346/245/255/347/265/214/345/226/266/350/253/226.md +2637 -2637
- package/lib/assets/docs/reference//347/222/260/345/242/203/345/244/211/346/225/260/347/256/241/347/220/206/343/202/254/343/202/244/343/203/211.md +665 -665
- package/lib/assets/docs/reference//350/246/201/344/273/266/345/256/232/347/276/251/343/202/254/343/202/244/343/203/211.md +1248 -1248
- package/lib/assets/docs/reference//350/250/200/350/252/236/345/210/245/351/226/213/347/231/272/343/202/254/343/202/244/343/203/211.md +518 -518
- package/lib/assets/docs/reference//351/201/213/345/226/266/347/256/241/347/220/206.md +1482 -1482
- package/lib/assets/docs/reference//351/201/213/347/224/250/343/202/271/343/202/257/343/203/252/343/203/227/343/203/210/344/275/234/346/210/220/343/202/254/343/202/244/343/203/211.md +421 -421
- package/lib/assets/docs/reference//351/201/213/347/224/250/350/246/201/344/273/266/345/256/232/347/276/251/343/202/254/343/202/244/343/203/211.md +392 -392
- package/lib/assets/docs/reference//351/226/213/347/231/272/343/202/254/343/202/244/343/203/211.md +299 -299
- package/lib/assets/docs/reference//351/235/236/346/251/237/350/203/275/350/246/201/344/273/266/345/256/232/347/276/251/343/202/254/343/202/244/343/203/211.md +1236 -1236
- package/lib/assets/docs/review/index.md +5 -5
- package/lib/assets/docs/strategy/index.md +1 -1
- package/lib/assets/docs/template/ADR.md +30 -30
- package/lib/assets/docs/template/AWS/343/202/271/343/203/206/343/203/274/343/202/270/343/203/263/343/202/260/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +1366 -1366
- package/lib/assets/docs/template/AWS/343/203/227/343/203/255/343/203/200/343/202/257/343/202/267/343/203/247/343/203/263/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +634 -634
- package/lib/assets/docs/template/README.md +50 -50
- package/lib/assets/docs/template/index.md +23 -23
- package/lib/assets/docs/template//343/201/276/343/201/232/343/201/223/343/202/214/343/202/222/350/252/255/343/202/202/343/201/206/343/203/252/343/202/271/343/203/210.md +12 -12
- package/lib/assets/docs/template//343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/351/226/213/347/231/272/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +547 -547
- package/lib/assets/docs/template//343/202/244/343/203/206/343/203/254/343/203/274/343/202/267/343/203/247/343/203/263/345/256/214/344/272/206/345/240/261/345/221/212/346/233/270.md +58 -58
- package/lib/assets/docs/template//343/202/244/343/203/263/343/202/273/343/203/227/343/202/267/343/203/247/343/203/263/343/203/207/343/203/203/343/202/255.md +13 -13
- package/lib/assets/docs/template//343/203/223/343/202/270/343/203/215/343/202/271/343/202/242/343/203/274/343/202/255/343/203/206/343/202/257/343/203/201/343/203/243.md +379 -379
- package/lib/assets/docs/template//344/274/201/346/245/255/345/210/206/346/236/220.md +573 -573
- package/lib/assets/docs/template//345/256/214/345/205/250/345/275/242/345/274/217/343/201/256/343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271.md +69 -69
- package/lib/assets/docs/template//350/246/201/344/273/266/345/256/232/347/276/251.md +669 -669
- package/lib/assets/docs/template//350/250/255/350/250/210.md +173 -173
- package/lib/assets/docs/template//351/226/213/347/231/272/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +688 -688
- package/lib/assets/gulpfile.js +25 -25
- package/lib/assets/mkdocs.yml +136 -136
- package/lib/assets/ops/docker/mkdoc/Dockerfile +19 -19
- package/lib/assets/ops/scripts/journal.js +180 -180
- package/lib/assets/ops/scripts/mkdocs.js +82 -82
- package/lib/assets/ops/scripts/release.js +431 -431
- package/lib/assets/ops/scripts/sonar_local.js +726 -726
- package/lib/assets/ops/scripts/ssh.js +190 -190
- package/lib/assets/ops/scripts/vault.js +299 -299
- package/lib/assets/package-lock.json +1653 -1653
- package/lib/assets/package.json +40 -40
- package/lib/gulpfile.js +37 -37
- package/package.json +41 -41
|
@@ -1,871 +1,871 @@
|
|
|
1
|
-
# Part III - 第 7 章:Either 型と代数的データ型
|
|
2
|
-
|
|
3
|
-
## 7.1 はじめに:Option の限界
|
|
4
|
-
|
|
5
|
-
前章で学んだ Option 型は、値の有無を型で表現する強力な手段でした。しかし、`None` は「なぜ失敗したか」の情報を持ちません。Either/Result 型は、失敗の理由をエラー値として保持し、より豊かなエラーハンドリングを実現します。
|
|
6
|
-
|
|
7
|
-
さらに本章では、**代数的データ型**(ADT: Algebraic Data Type)を学びます。ADT は「直和型」と「直積型」の組み合わせで、ドメインの概念を正確にモデリングする関数型プログラミングの基盤です。
|
|
8
|
-
|
|
9
|
-
本章では、11 言語での Either/Result と ADT の実装を横断的に比較し、以下を明らかにします:
|
|
10
|
-
|
|
11
|
-
- Either/Result の実装方式の違い(組み込み vs ライブラリ vs タプル/マップ)
|
|
12
|
-
- ADT の表現方法(sealed trait, enum, 判別共用体, discriminated union)
|
|
13
|
-
- パターンマッチの網羅性チェックの言語間差異
|
|
14
|
-
|
|
15
|
-
```plantuml
|
|
16
|
-
@startuml
|
|
17
|
-
!theme plain
|
|
18
|
-
|
|
19
|
-
rectangle "Option" #LightYellow {
|
|
20
|
-
card "Some(value)" as os
|
|
21
|
-
card "None(理由なし)" as on
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
rectangle "Either / Result" #LightGreen {
|
|
25
|
-
card "Right(value) / Ok(value)" as er
|
|
26
|
-
card "Left(error) / Err(error)" as el
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
rectangle "ADT" #LightBlue {
|
|
30
|
-
card "直和型(Sum Type)\nA | B | C" as sum
|
|
31
|
-
card "直積型(Product Type)\nA × B × C" as prod
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
on -right-> el : "失敗の理由を追加"
|
|
35
|
-
|
|
36
|
-
@enduml
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## 7.2 共通の本質:Either = Right | Left
|
|
42
|
-
|
|
43
|
-
11 言語すべてに共通する Either/Result の構造は、**成功と失敗の 2 つのケース**を持つ型です:
|
|
44
|
-
|
|
45
|
-
1. **Right / Ok / Success**: 処理が成功し、値を保持する
|
|
46
|
-
2. **Left / Err / Failure**: 処理が失敗し、エラー情報を保持する
|
|
47
|
-
|
|
48
|
-
3 つの言語グループから代表例を見てみましょう:
|
|
49
|
-
|
|
50
|
-
```haskell
|
|
51
|
-
-- Haskell: Either 型(言語組み込み)
|
|
52
|
-
data Either e a = Left e | Right a
|
|
53
|
-
|
|
54
|
-
-- 使用例
|
|
55
|
-
extractName :: String -> Either String String
|
|
56
|
-
extractName rawShow =
|
|
57
|
-
case elemIndex '(' rawShow of
|
|
58
|
-
Just idx | idx > 0 -> Right $ trim $ take idx rawShow
|
|
59
|
-
_ -> Left $ "Can't extract name from " ++ rawShow
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
```rust
|
|
63
|
-
// Rust: Result 型(言語組み込み)
|
|
64
|
-
pub fn extract_name(raw_show: &str) -> Result<String, String> {
|
|
65
|
-
let bracket_open = raw_show
|
|
66
|
-
.find('(')
|
|
67
|
-
.ok_or_else(|| format!("Can't find '(' in {}", raw_show))?;
|
|
68
|
-
|
|
69
|
-
if bracket_open > 0 {
|
|
70
|
-
Ok(raw_show[..bracket_open].trim().to_string())
|
|
71
|
-
} else {
|
|
72
|
-
Err(format!("Can't extract name from {}", raw_show))
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
```scala
|
|
78
|
-
// Scala: Either 型(標準ライブラリ)
|
|
79
|
-
def extractName(show: String): Either[String, String] = {
|
|
80
|
-
val bracketOpen = show.indexOf('(')
|
|
81
|
-
if (bracketOpen > 0) Right(show.substring(0, bracketOpen).trim)
|
|
82
|
-
else Left(s"Can't extract name from $show")
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
## 7.3 Either/Result の実装方式
|
|
89
|
-
|
|
90
|
-
### アプローチ 1: 言語組み込み
|
|
91
|
-
|
|
92
|
-
| 言語 | 型名 | 成功 | 失敗 | 特徴 |
|
|
93
|
-
|------|------|------|------|------|
|
|
94
|
-
| **Haskell** | `Either e a` | `Right a` | `Left e` | 最も古典的な Either |
|
|
95
|
-
| **Rust** | `Result<T, E>` | `Ok(T)` | `Err(E)` | `?` 演算子で簡潔な伝播 |
|
|
96
|
-
| **F#** | `Result<'T, 'E>` | `Ok value` | `Error e` | パイプ + パターンマッチ |
|
|
97
|
-
|
|
98
|
-
### アプローチ 2: ライブラリ提供
|
|
99
|
-
|
|
100
|
-
| 言語 | ライブラリ | 型名 | 成功 | 失敗 |
|
|
101
|
-
|------|-----------|------|------|------|
|
|
102
|
-
| **Scala** | 標準ライブラリ | `Either[E, A]` | `Right(a)` | `Left(e)` |
|
|
103
|
-
| **Java** | Vavr | `Either<L, R>` | `Either.right(r)` | `Either.left(l)` |
|
|
104
|
-
| **C#** | LanguageExt | `Either<L, R>` | `Right(r)` | `Left(l)` |
|
|
105
|
-
| **TypeScript** | fp-ts | `Either<E, A>` | `E.right(a)` | `E.left(e)` |
|
|
106
|
-
| **Python** | returns | `Result[T, E]` | `Success(t)` | `Failure(e)` |
|
|
107
|
-
| **Ruby** | dry-monads | `Result` | `Success(t)` | `Failure(e)` |
|
|
108
|
-
|
|
109
|
-
### アプローチ 3: タプル / マップベース
|
|
110
|
-
|
|
111
|
-
| 言語 | 構造 | 成功 | 失敗 |
|
|
112
|
-
|------|------|------|------|
|
|
113
|
-
| **Elixir** | タプル | `{:ok, value}` | `{:error, reason}` |
|
|
114
|
-
| **Clojure** | マップ | `{:status :ok, :value v}` | `{:status :error, :error msg}` |
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
## 7.4 TV 番組パース:Either による合成
|
|
119
|
-
|
|
120
|
-
Option 版と同じ TV 番組パースを Either で実装し、**失敗の理由**が伝播する様子を比較します。
|
|
121
|
-
|
|
122
|
-
### 代表 3 言語の比較
|
|
123
|
-
|
|
124
|
-
**Haskell**: do 記法
|
|
125
|
-
|
|
126
|
-
```haskell
|
|
127
|
-
parseShowE :: String -> Either String TvShow
|
|
128
|
-
parseShowE rawShow = do
|
|
129
|
-
name <- extractNameE rawShow
|
|
130
|
-
yearStart <- extractYearStartE rawShow `orElseE` extractSingleYearE rawShow
|
|
131
|
-
yearEnd <- extractYearEndE rawShow `orElseE` extractSingleYearE rawShow
|
|
132
|
-
return $ TvShow name yearStart yearEnd
|
|
133
|
-
|
|
134
|
-
-- 失敗例
|
|
135
|
-
parseShowE "Invalid"
|
|
136
|
-
-- Left "Can't extract name from Invalid"(失敗の理由が残る)
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
**Scala**: for 内包表記
|
|
140
|
-
|
|
141
|
-
```scala
|
|
142
|
-
def parseShow(rawShow: String): Either[String, TvShow] =
|
|
143
|
-
for {
|
|
144
|
-
name <- extractName(rawShow)
|
|
145
|
-
yearStart <- extractYearStart(rawShow).orElse(extractSingleYear(rawShow))
|
|
146
|
-
yearEnd <- extractYearEnd(rawShow).orElse(extractSingleYear(rawShow))
|
|
147
|
-
} yield TvShow(name, yearStart, yearEnd)
|
|
148
|
-
|
|
149
|
-
// 失敗例
|
|
150
|
-
parseShow("Invalid")
|
|
151
|
-
// Left("Can't extract name from Invalid")
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
**Rust**: ? 演算子
|
|
155
|
-
|
|
156
|
-
```rust
|
|
157
|
-
pub fn parse_show(raw_show: &str) -> Result<TvShow, String> {
|
|
158
|
-
let name = extract_name(raw_show)?;
|
|
159
|
-
let year_start = extract_year_start(raw_show)
|
|
160
|
-
.or_else(|_| extract_single_year(raw_show))?;
|
|
161
|
-
let year_end = extract_year_end(raw_show)
|
|
162
|
-
.or_else(|_| extract_single_year(raw_show))?;
|
|
163
|
-
|
|
164
|
-
Ok(TvShow::new(&name, year_start, year_end))
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// 失敗例
|
|
168
|
-
parse_show("Invalid")
|
|
169
|
-
// Err("Can't extract name from Invalid")
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### 全 11 言語の実装
|
|
173
|
-
|
|
174
|
-
#### 関数型ファースト言語
|
|
175
|
-
|
|
176
|
-
<details>
|
|
177
|
-
<summary>Haskell 実装</summary>
|
|
178
|
-
|
|
179
|
-
```haskell
|
|
180
|
-
parseShowE :: String -> Either String TvShow
|
|
181
|
-
parseShowE rawShow = do
|
|
182
|
-
name <- extractNameE rawShow
|
|
183
|
-
yearStart <- extractYearStartE rawShow `orElseE` extractSingleYearE rawShow
|
|
184
|
-
yearEnd <- extractYearEndE rawShow `orElseE` extractSingleYearE rawShow
|
|
185
|
-
return $ TvShow name yearStart yearEnd
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
Haskell の `Either` は `Monad` インスタンスを持ち、do 記法で `Maybe` と同じように合成できます。
|
|
189
|
-
|
|
190
|
-
</details>
|
|
191
|
-
|
|
192
|
-
<details>
|
|
193
|
-
<summary>Clojure 実装</summary>
|
|
194
|
-
|
|
195
|
-
```clojure
|
|
196
|
-
(defn ok [value] {:status :ok :value value})
|
|
197
|
-
(defn error [message] {:status :error :error message})
|
|
198
|
-
|
|
199
|
-
(defn result-flatmap [f result]
|
|
200
|
-
(if (= (:status result) :ok)
|
|
201
|
-
(f (:value result))
|
|
202
|
-
result))
|
|
203
|
-
|
|
204
|
-
(defn parse-show-result [raw-show]
|
|
205
|
-
(result-flatmap
|
|
206
|
-
(fn [name]
|
|
207
|
-
(let [year-start (result-or-else
|
|
208
|
-
(extract-year-start-result raw-show)
|
|
209
|
-
#(extract-single-year-result raw-show))
|
|
210
|
-
year-end (result-or-else
|
|
211
|
-
(extract-year-end-result raw-show)
|
|
212
|
-
#(extract-single-year-result raw-show))]
|
|
213
|
-
(result-flatmap
|
|
214
|
-
(fn [ys]
|
|
215
|
-
(result-flatmap
|
|
216
|
-
(fn [ye] (ok {:title name :start ys :end ye}))
|
|
217
|
-
year-end))
|
|
218
|
-
year-start)))
|
|
219
|
-
(extract-name-result raw-show)))
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
Clojure では専用の型を持たないため、マップベースの Result パターンと `result-flatmap` 関数を手動で実装します。
|
|
223
|
-
|
|
224
|
-
</details>
|
|
225
|
-
|
|
226
|
-
<details>
|
|
227
|
-
<summary>Elixir 実装</summary>
|
|
228
|
-
|
|
229
|
-
```elixir
|
|
230
|
-
def parse_show(raw_show) do
|
|
231
|
-
with {:ok, name} <- extract_name(raw_show),
|
|
232
|
-
{:ok, year_start} <- or_else(extract_year_start(raw_show),
|
|
233
|
-
fn -> extract_single_year(raw_show) end),
|
|
234
|
-
{:ok, year_end} <- or_else(extract_year_end(raw_show),
|
|
235
|
-
fn -> extract_single_year(raw_show) end) do
|
|
236
|
-
{:ok, %TvShow{title: name, start: year_start, end_year: year_end}}
|
|
237
|
-
end
|
|
238
|
-
end
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
Elixir の `with` 式は、パターンマッチが失敗すると最初の不一致を返します。`{:ok, value}` / `{:error, reason}` のタプルパターンは Erlang/OTP の伝統です。
|
|
242
|
-
|
|
243
|
-
</details>
|
|
244
|
-
|
|
245
|
-
<details>
|
|
246
|
-
<summary>F# 実装</summary>
|
|
247
|
-
|
|
248
|
-
```fsharp
|
|
249
|
-
let parseShow (rawShow: string) : Result<TvShow, string> =
|
|
250
|
-
match extractName rawShow with
|
|
251
|
-
| Error e -> Error e
|
|
252
|
-
| Ok name ->
|
|
253
|
-
let yearStart =
|
|
254
|
-
extractYearStart rawShow
|
|
255
|
-
|> Result.orElse (extractSingleYear rawShow)
|
|
256
|
-
let yearEnd =
|
|
257
|
-
extractYearEnd rawShow
|
|
258
|
-
|> Result.orElse (extractSingleYear rawShow)
|
|
259
|
-
match yearStart, yearEnd with
|
|
260
|
-
| Ok start, Ok endYear ->
|
|
261
|
-
Ok { Title = name; Start = start; End = endYear }
|
|
262
|
-
| Error e, _ -> Error e
|
|
263
|
-
| _, Error e -> Error e
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
F# ではパターンマッチで `Ok` / `Error` を明示的に処理します。
|
|
267
|
-
|
|
268
|
-
</details>
|
|
269
|
-
|
|
270
|
-
#### マルチパラダイム言語
|
|
271
|
-
|
|
272
|
-
<details>
|
|
273
|
-
<summary>Scala 実装</summary>
|
|
274
|
-
|
|
275
|
-
```scala
|
|
276
|
-
def parseShow(rawShow: String): Either[String, TvShow] =
|
|
277
|
-
for {
|
|
278
|
-
name <- extractName(rawShow)
|
|
279
|
-
yearStart <- extractYearStart(rawShow).orElse(extractSingleYear(rawShow))
|
|
280
|
-
yearEnd <- extractYearEnd(rawShow).orElse(extractSingleYear(rawShow))
|
|
281
|
-
} yield TvShow(name, yearStart, yearEnd)
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
</details>
|
|
285
|
-
|
|
286
|
-
<details>
|
|
287
|
-
<summary>Rust 実装</summary>
|
|
288
|
-
|
|
289
|
-
```rust
|
|
290
|
-
pub fn parse_show(raw_show: &str) -> Result<TvShow, String> {
|
|
291
|
-
let name = extract_name(raw_show)?;
|
|
292
|
-
let year_start = extract_year_start(raw_show)
|
|
293
|
-
.or_else(|_| extract_single_year(raw_show))?;
|
|
294
|
-
let year_end = extract_year_end(raw_show)
|
|
295
|
-
.or_else(|_| extract_single_year(raw_show))?;
|
|
296
|
-
|
|
297
|
-
Ok(TvShow::new(&name, year_start, year_end))
|
|
298
|
-
}
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
Rust の `?` 演算子は `Option` と `Result` の両方で使えます。`or_else(|_| ...)` のクロージャ引数 `_` はエラー値を無視することを示します。
|
|
302
|
-
|
|
303
|
-
</details>
|
|
304
|
-
|
|
305
|
-
<details>
|
|
306
|
-
<summary>TypeScript (fp-ts) 実装</summary>
|
|
307
|
-
|
|
308
|
-
```typescript
|
|
309
|
-
import * as E from 'fp-ts/Either'
|
|
310
|
-
|
|
311
|
-
const parseShow = (rawShow: string): E.Either<string, TvShow> =>
|
|
312
|
-
pipe(
|
|
313
|
-
E.Do,
|
|
314
|
-
E.bind('name', () => extractName(rawShow)),
|
|
315
|
-
E.bind('start', () =>
|
|
316
|
-
pipe(
|
|
317
|
-
extractYearStart(rawShow),
|
|
318
|
-
E.orElse(() => extractSingleYear(rawShow))
|
|
319
|
-
)
|
|
320
|
-
),
|
|
321
|
-
E.bind('end', () =>
|
|
322
|
-
pipe(
|
|
323
|
-
extractYearEnd(rawShow),
|
|
324
|
-
E.orElse(() => extractSingleYear(rawShow))
|
|
325
|
-
)
|
|
326
|
-
),
|
|
327
|
-
E.map(({ name, start, end }) => ({ title: name, start, end }))
|
|
328
|
-
)
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
</details>
|
|
332
|
-
|
|
333
|
-
#### OOP + FP ライブラリ言語
|
|
334
|
-
|
|
335
|
-
<details>
|
|
336
|
-
<summary>Java (Vavr) 実装</summary>
|
|
337
|
-
|
|
338
|
-
```java
|
|
339
|
-
public static Either<String, TvShow> parseShow(String rawShow) {
|
|
340
|
-
return extractName(rawShow).flatMap(name ->
|
|
341
|
-
extractYearStart(rawShow).orElse(() -> extractSingleYear(rawShow))
|
|
342
|
-
.flatMap(yearStart ->
|
|
343
|
-
extractYearEnd(rawShow).orElse(() -> extractSingleYear(rawShow))
|
|
344
|
-
.map(yearEnd -> new TvShow(name, yearStart, yearEnd))
|
|
345
|
-
)
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
</details>
|
|
351
|
-
|
|
352
|
-
<details>
|
|
353
|
-
<summary>C# (LanguageExt) 実装</summary>
|
|
354
|
-
|
|
355
|
-
```csharp
|
|
356
|
-
Either<string, TvShow> ParseShow(string rawShow) =>
|
|
357
|
-
from name in ExtractName(rawShow)
|
|
358
|
-
from yearStart in ExtractYearStart(rawShow) || ExtractSingleYear(rawShow)
|
|
359
|
-
from yearEnd in ExtractYearEnd(rawShow) || ExtractSingleYear(rawShow)
|
|
360
|
-
select new TvShow(name, yearStart, yearEnd);
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
C# の LINQ + `||` 演算子で Scala の for 内包表記に匹敵する簡潔さを実現しています。
|
|
364
|
-
|
|
365
|
-
</details>
|
|
366
|
-
|
|
367
|
-
<details>
|
|
368
|
-
<summary>Python (returns) 実装</summary>
|
|
369
|
-
|
|
370
|
-
```python
|
|
371
|
-
from returns.result import Result, Success, Failure
|
|
372
|
-
|
|
373
|
-
def parse_show(raw_show: str) -> Result[TvShow, str]:
|
|
374
|
-
name = extract_name_result(raw_show)
|
|
375
|
-
year_start = extract_year_start_result(raw_show).lash(
|
|
376
|
-
lambda _: extract_single_year_result(raw_show)
|
|
377
|
-
)
|
|
378
|
-
year_end = extract_year_end_result(raw_show).lash(
|
|
379
|
-
lambda _: extract_single_year_result(raw_show)
|
|
380
|
-
)
|
|
381
|
-
|
|
382
|
-
return name.bind(
|
|
383
|
-
lambda n: year_start.bind(
|
|
384
|
-
lambda s: year_end.map(lambda e: TvShow(n, s, e))
|
|
385
|
-
)
|
|
386
|
-
)
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
</details>
|
|
390
|
-
|
|
391
|
-
<details>
|
|
392
|
-
<summary>Ruby (dry-monads) 実装</summary>
|
|
393
|
-
|
|
394
|
-
```ruby
|
|
395
|
-
def parse_show(raw_show)
|
|
396
|
-
name = extract_name(raw_show)
|
|
397
|
-
year_start = extract_year_start(raw_show).or(extract_single_year(raw_show))
|
|
398
|
-
year_end = extract_year_end(raw_show).or(extract_single_year(raw_show))
|
|
399
|
-
|
|
400
|
-
name.bind do |n|
|
|
401
|
-
year_start.bind do |ys|
|
|
402
|
-
year_end.fmap do |ye|
|
|
403
|
-
TvShow.new(title: n, start_year: ys, end_year: ye)
|
|
404
|
-
end
|
|
405
|
-
end
|
|
406
|
-
end
|
|
407
|
-
end
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
</details>
|
|
411
|
-
|
|
412
|
-
---
|
|
413
|
-
|
|
414
|
-
## 7.5 代数的データ型(ADT)
|
|
415
|
-
|
|
416
|
-
ADT は関数型プログラミングのドメインモデリングの基盤です。**直和型**(「A または B」)と**直積型**(「A かつ B」)の組み合わせで、ドメインの概念を型で正確に表現します。
|
|
417
|
-
|
|
418
|
-
### 直和型の例:YearsActive
|
|
419
|
-
|
|
420
|
-
アーティストの活動期間は「活動中」か「活動終了」のどちらかです:
|
|
421
|
-
|
|
422
|
-
```plantuml
|
|
423
|
-
@startuml
|
|
424
|
-
!theme plain
|
|
425
|
-
|
|
426
|
-
rectangle "YearsActive(直和型)" #LightBlue {
|
|
427
|
-
card "StillActive(since: Int)" as sa #LightGreen
|
|
428
|
-
card "ActiveBetween(start: Int, end: Int)" as ab #LightYellow
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
note bottom of sa : 現在も活動中
|
|
432
|
-
note bottom of ab : 活動を終了
|
|
433
|
-
|
|
434
|
-
@enduml
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
### 代表 3 言語の ADT 定義
|
|
438
|
-
|
|
439
|
-
**Haskell**: data 型
|
|
440
|
-
|
|
441
|
-
```haskell
|
|
442
|
-
data MusicGenre = HeavyMetal | Pop | HardRock | Grunge
|
|
443
|
-
deriving (Show, Eq)
|
|
444
|
-
|
|
445
|
-
data YearsActive
|
|
446
|
-
= StillActive Int
|
|
447
|
-
| ActiveBetween Int Int
|
|
448
|
-
deriving (Show, Eq)
|
|
449
|
-
|
|
450
|
-
data Artist = Artist
|
|
451
|
-
{ artistName :: String
|
|
452
|
-
, artistGenre :: MusicGenre
|
|
453
|
-
, artistOrigin :: Location
|
|
454
|
-
, artistYearsActive :: YearsActive
|
|
455
|
-
}
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
**Rust**: enum
|
|
459
|
-
|
|
460
|
-
```rust
|
|
461
|
-
#[derive(Debug, Clone, PartialEq)]
|
|
462
|
-
pub enum MusicGenre {
|
|
463
|
-
HeavyMetal,
|
|
464
|
-
Pop,
|
|
465
|
-
HardRock,
|
|
466
|
-
Jazz,
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
#[derive(Debug, Clone, PartialEq)]
|
|
470
|
-
pub enum YearsActive {
|
|
471
|
-
StillActive { since: i32 },
|
|
472
|
-
ActiveBetween { start: i32, end: i32 },
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
pub struct Artist {
|
|
476
|
-
pub name: String,
|
|
477
|
-
pub genre: MusicGenre,
|
|
478
|
-
pub origin: Location,
|
|
479
|
-
pub years_active: YearsActive,
|
|
480
|
-
}
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
**Scala**: enum(Scala 3)
|
|
484
|
-
|
|
485
|
-
```scala
|
|
486
|
-
enum MusicGenre {
|
|
487
|
-
case HeavyMetal, Pop, HardRock
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
enum YearsActive {
|
|
491
|
-
case StillActive(since: Int)
|
|
492
|
-
case ActiveBetween(start: Int, end: Int)
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
case class Artist(
|
|
496
|
-
name: String,
|
|
497
|
-
genre: MusicGenre,
|
|
498
|
-
origin: Location,
|
|
499
|
-
yearsActive: YearsActive
|
|
500
|
-
)
|
|
501
|
-
```
|
|
502
|
-
|
|
503
|
-
### 全 11 言語の ADT 表現
|
|
504
|
-
|
|
505
|
-
| 言語 | 直和型の構文 | 直積型の構文 | 網羅性チェック |
|
|
506
|
-
|------|------------|------------|-------------|
|
|
507
|
-
| **Haskell** | `data T = A \| B` | `data T = T { field :: Type }` | コンパイラ警告 |
|
|
508
|
-
| **Rust** | `enum T { A, B }` | `struct T { field: Type }` | コンパイルエラー |
|
|
509
|
-
| **F#** | `type T = A \| B` | `type T = { Field: Type }` | コンパイラ警告 |
|
|
510
|
-
| **Scala** | `enum T { case A; case B }` | `case class T(field: Type)` | コンパイラ警告 |
|
|
511
|
-
| **Java** | `sealed interface T` + `record` | `record T(Type field)` | コンパイルエラー(21+) |
|
|
512
|
-
| **C#** | `abstract record` + 派生 record | `record T(Type Field)` | switch 式で警告 |
|
|
513
|
-
| **TypeScript** | `type T = { _tag: 'A' } \| { _tag: 'B' }` | `interface T { field: Type }` | なし(型レベル) |
|
|
514
|
-
| **Python** | `Enum` + `@dataclass` | `@dataclass(frozen=True)` | match(3.10+) |
|
|
515
|
-
| **Clojure** | マップ + `:type` タグ | マップ | なし |
|
|
516
|
-
| **Elixir** | タプル `{:tag, ...}` | `defstruct` | なし |
|
|
517
|
-
| **Ruby** | モジュール + クラス | `Struct` | case when |
|
|
518
|
-
|
|
519
|
-
<details>
|
|
520
|
-
<summary>全 11 言語の ADT 定義</summary>
|
|
521
|
-
|
|
522
|
-
**F#**(判別共用体):
|
|
523
|
-
```fsharp
|
|
524
|
-
type MusicGenre = HeavyMetal | Pop | HardRock | Jazz
|
|
525
|
-
|
|
526
|
-
type YearsActive =
|
|
527
|
-
| StillActive of since: int
|
|
528
|
-
| ActiveBetween of start: int * endYear: int
|
|
529
|
-
```
|
|
530
|
-
|
|
531
|
-
**Java**(sealed interface + record):
|
|
532
|
-
```java
|
|
533
|
-
public sealed interface YearsActive permits StillActive, ActiveBetween {}
|
|
534
|
-
public record StillActive(int since) implements YearsActive {}
|
|
535
|
-
public record ActiveBetween(int start, int end) implements YearsActive {}
|
|
536
|
-
```
|
|
537
|
-
|
|
538
|
-
**C#**(abstract record):
|
|
539
|
-
```csharp
|
|
540
|
-
public abstract record YearsActive;
|
|
541
|
-
public record StillActive(int Since) : YearsActive;
|
|
542
|
-
public record ActiveBetween(int Start, int EndYear) : YearsActive;
|
|
543
|
-
```
|
|
544
|
-
|
|
545
|
-
**TypeScript**(discriminated union):
|
|
546
|
-
```typescript
|
|
547
|
-
type YearsActive =
|
|
548
|
-
| { readonly _tag: 'StillActive'; readonly since: number }
|
|
549
|
-
| { readonly _tag: 'ActiveBetween'; readonly start: number; readonly end: number }
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
**Clojure**(マップ + タグ):
|
|
553
|
-
```clojure
|
|
554
|
-
(defn still-active [since]
|
|
555
|
-
{:type :still-active :since since})
|
|
556
|
-
|
|
557
|
-
(defn active-between [start end]
|
|
558
|
-
{:type :active-between :start start :end end})
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
**Elixir**(タプル):
|
|
562
|
-
```elixir
|
|
563
|
-
# {:still_active, since}
|
|
564
|
-
# {:active_between, start, end_year}
|
|
565
|
-
```
|
|
566
|
-
|
|
567
|
-
**Python**(dataclass + Union):
|
|
568
|
-
```python
|
|
569
|
-
@dataclass(frozen=True)
|
|
570
|
-
class StillActive:
|
|
571
|
-
since: int
|
|
572
|
-
|
|
573
|
-
@dataclass(frozen=True)
|
|
574
|
-
class ActiveBetween:
|
|
575
|
-
start: int
|
|
576
|
-
end: int
|
|
577
|
-
|
|
578
|
-
YearsActive = StillActive | ActiveBetween
|
|
579
|
-
```
|
|
580
|
-
|
|
581
|
-
**Ruby**(Module + Classes):
|
|
582
|
-
```ruby
|
|
583
|
-
module YearsActive
|
|
584
|
-
class StillActive
|
|
585
|
-
attr_reader :since
|
|
586
|
-
def initialize(since) = @since = since
|
|
587
|
-
end
|
|
588
|
-
|
|
589
|
-
class ActiveBetween
|
|
590
|
-
attr_reader :start_year, :end_year
|
|
591
|
-
def initialize(start_year, end_year)
|
|
592
|
-
@start_year = start_year
|
|
593
|
-
@end_year = end_year
|
|
594
|
-
end
|
|
595
|
-
end
|
|
596
|
-
end
|
|
597
|
-
```
|
|
598
|
-
|
|
599
|
-
</details>
|
|
600
|
-
|
|
601
|
-
---
|
|
602
|
-
|
|
603
|
-
## 7.6 パターンマッチ:ADT の安全な処理
|
|
604
|
-
|
|
605
|
-
ADT の各ケースを処理するパターンマッチは、関数型プログラミングの中核です。アーティストが特定期間に活動していたかを判定する関数で比較します。
|
|
606
|
-
|
|
607
|
-
### 代表 3 言語の比較
|
|
608
|
-
|
|
609
|
-
**Haskell**:
|
|
610
|
-
|
|
611
|
-
```haskell
|
|
612
|
-
wasArtistActive :: Artist -> Int -> Int -> Bool
|
|
613
|
-
wasArtistActive artist yearStart yearEnd =
|
|
614
|
-
case artistYearsActive artist of
|
|
615
|
-
StillActive since -> since <= yearEnd
|
|
616
|
-
ActiveBetween start end_ -> start <= yearEnd && end_ >= yearStart
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
**Rust**:
|
|
620
|
-
|
|
621
|
-
```rust
|
|
622
|
-
pub fn was_artist_active(artist: &Artist, year_start: i32, year_end: i32) -> bool {
|
|
623
|
-
match &artist.years_active {
|
|
624
|
-
YearsActive::StillActive { since } => *since <= year_end,
|
|
625
|
-
YearsActive::ActiveBetween { start, end } =>
|
|
626
|
-
*start <= year_end && *end >= year_start,
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
```
|
|
630
|
-
|
|
631
|
-
**Scala**:
|
|
632
|
-
|
|
633
|
-
```scala
|
|
634
|
-
def wasArtistActive(artist: Artist, yearStart: Int, yearEnd: Int): Boolean =
|
|
635
|
-
artist.yearsActive match {
|
|
636
|
-
case StillActive(since) => since <= yearEnd
|
|
637
|
-
case ActiveBetween(start, end) => start <= yearEnd && end >= yearStart
|
|
638
|
-
}
|
|
639
|
-
```
|
|
640
|
-
|
|
641
|
-
### 網羅性チェックの比較
|
|
642
|
-
|
|
643
|
-
| レベル | 言語 | 挙動 |
|
|
644
|
-
|--------|------|------|
|
|
645
|
-
| **コンパイルエラー** | Rust, Java (21+ sealed) | ケースが不足するとコンパイルが失敗する |
|
|
646
|
-
| **コンパイラ警告** | Haskell, Scala, F# | 警告が出るが、コンパイルは通る |
|
|
647
|
-
| **IDE 警告のみ** | C#, TypeScript | エディタが警告するが言語レベルでは強制しない |
|
|
648
|
-
| **なし** | Clojure, Elixir, Python, Ruby | 動的型付けのため網羅性チェックなし |
|
|
649
|
-
|
|
650
|
-
**発見**: Rust は `match` で全ケースを処理しないとコンパイルエラーになる唯一の言語です。これにより、ADT にケースを追加した際に、処理漏れを確実に検出できます。
|
|
651
|
-
|
|
652
|
-
---
|
|
653
|
-
|
|
654
|
-
## 7.7 Option と Either の変換
|
|
655
|
-
|
|
656
|
-
Option と Either は相互に変換可能です。失敗理由を付加して Option → Either、理由を捨てて Either → Option に変換します。
|
|
657
|
-
|
|
658
|
-
### 代表的な変換パターン
|
|
659
|
-
|
|
660
|
-
| 方向 | Scala | Haskell | Rust | F# |
|
|
661
|
-
|------|-------|---------|------|----|
|
|
662
|
-
| Option → Either | `opt.toRight("error")` | `maybeToEither "error" mb` | `opt.ok_or("error")` | `Option.toResult` |
|
|
663
|
-
| Either → Option | `either.toOption` | `eitherToMaybe e` | `result.ok()` | `Result.toOption` |
|
|
664
|
-
|
|
665
|
-
```scala
|
|
666
|
-
// Scala
|
|
667
|
-
val opt: Option[Int] = Some(42)
|
|
668
|
-
val either: Either[String, Int] = opt.toRight("Value not found")
|
|
669
|
-
// Right(42)
|
|
670
|
-
|
|
671
|
-
val back: Option[Int] = either.toOption
|
|
672
|
-
// Some(42)
|
|
673
|
-
```
|
|
674
|
-
|
|
675
|
-
```rust
|
|
676
|
-
// Rust
|
|
677
|
-
let opt: Option<i32> = Some(42);
|
|
678
|
-
let result: Result<i32, &str> = opt.ok_or("Value not found");
|
|
679
|
-
// Ok(42)
|
|
680
|
-
|
|
681
|
-
let back: Option<i32> = result.ok();
|
|
682
|
-
// Some(42)
|
|
683
|
-
```
|
|
684
|
-
|
|
685
|
-
---
|
|
686
|
-
|
|
687
|
-
## 7.8 比較分析:3 つの発見
|
|
688
|
-
|
|
689
|
-
### 発見 1: Either/Result の命名は 3 系統に分かれる
|
|
690
|
-
|
|
691
|
-
| 系統 | 成功 | 失敗 | 言語 |
|
|
692
|
-
|------|------|------|------|
|
|
693
|
-
| **Either 系** | `Right` | `Left` | Haskell, Scala, Java (Vavr), C# (LE), TypeScript (fp-ts) |
|
|
694
|
-
| **Result 系** | `Ok` | `Err` / `Error` | Rust, F# |
|
|
695
|
-
| **Success/Failure 系** | `Success` | `Failure` | Python (returns), Ruby (dry-monads) |
|
|
696
|
-
|
|
697
|
-
Either 系は数学的な「左右」に由来し、Result 系は実用的な命名です。Elixir の `{:ok, value}` / `{:error, reason}` は Result 系のタプル表現です。
|
|
698
|
-
|
|
699
|
-
### 発見 2: ADT の表現力は言語の型システムに依存する
|
|
700
|
-
|
|
701
|
-
```plantuml
|
|
702
|
-
@startuml
|
|
703
|
-
!theme plain
|
|
704
|
-
left to right direction
|
|
705
|
-
|
|
706
|
-
rectangle "Level 1: ファーストクラス ADT" #LightGreen {
|
|
707
|
-
card "Haskell (data)" as h
|
|
708
|
-
card "Rust (enum)" as rs
|
|
709
|
-
card "F# (判別共用体)" as fs
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
rectangle "Level 2: 型システムで近似" #LightBlue {
|
|
713
|
-
card "Scala (enum)" as sc
|
|
714
|
-
card "Java (sealed)" as jv
|
|
715
|
-
card "C# (abstract record)" as cs
|
|
716
|
-
card "TypeScript (discriminated union)" as ts
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
rectangle "Level 3: 慣習的 ADT" #LightYellow {
|
|
720
|
-
card "Python (dataclass + Union)" as py
|
|
721
|
-
card "Ruby (Module + Class)" as rb
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
rectangle "Level 4: データで表現" #LightCoral {
|
|
725
|
-
card "Clojure (:type タグ)" as clj
|
|
726
|
-
card "Elixir (タプル)" as ex
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
@enduml
|
|
730
|
-
```
|
|
731
|
-
|
|
732
|
-
Haskell, Rust, F# はファーストクラスの ADT を持ち、コンパイラによる網羅性チェックが保証されます。TypeScript の discriminated union は `_tag` フィールドで近似しますが、言語レベルの保証はありません。
|
|
733
|
-
|
|
734
|
-
### 発見 3: Either の合成構文は Option と共通
|
|
735
|
-
|
|
736
|
-
前章の Option と本章の Either は、同じ合成構文(for / do / LINQ / `?`)で使えます。これは両者が同じ**モナドインターフェース**を共有しているからです:
|
|
737
|
-
|
|
738
|
-
```
|
|
739
|
-
Option.flatMap: Option[A] → (A → Option[B]) → Option[B]
|
|
740
|
-
Either.flatMap: Either[E,A] → (A → Either[E,B]) → Either[E,B]
|
|
741
|
-
```
|
|
742
|
-
|
|
743
|
-
Scala の for 内包表記、Haskell の do 記法、Rust の `?` 演算子は、Option と Either の両方で同じように機能します。
|
|
744
|
-
|
|
745
|
-
---
|
|
746
|
-
|
|
747
|
-
## 7.9 言語固有の特徴
|
|
748
|
-
|
|
749
|
-
### Rust: カスタムエラー型と ? 演算子
|
|
750
|
-
|
|
751
|
-
Rust では文字列ではなく専用の enum でエラーを表現するのが慣習です:
|
|
752
|
-
|
|
753
|
-
```rust
|
|
754
|
-
#[derive(Debug, Clone, PartialEq)]
|
|
755
|
-
pub enum ParseError {
|
|
756
|
-
MissingName,
|
|
757
|
-
MissingYear,
|
|
758
|
-
InvalidYear(String),
|
|
759
|
-
MissingBracket,
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
pub fn extract_name(raw_show: &str) -> Result<String, ParseError> {
|
|
763
|
-
let bracket_open = raw_show.find('(').ok_or(ParseError::MissingBracket)?;
|
|
764
|
-
if bracket_open > 0 {
|
|
765
|
-
Ok(raw_show[..bracket_open].trim().to_string())
|
|
766
|
-
} else {
|
|
767
|
-
Err(ParseError::MissingName)
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
```
|
|
771
|
-
|
|
772
|
-
エラー型を enum にすることで、パターンマッチでエラーの種類ごとに処理を分けられます。
|
|
773
|
-
|
|
774
|
-
### Elixir: {:ok, value} / {:error, reason} のタプルパターン
|
|
775
|
-
|
|
776
|
-
Elixir のタプルパターンは Erlang/OTP の伝統を引き継ぎ、エコシステム全体で統一されています:
|
|
777
|
-
|
|
778
|
-
```elixir
|
|
779
|
-
case File.read("config.json") do
|
|
780
|
-
{:ok, content} -> Jason.decode(content)
|
|
781
|
-
{:error, :enoent} -> {:error, "File not found"}
|
|
782
|
-
{:error, reason} -> {:error, "Failed: #{reason}"}
|
|
783
|
-
end
|
|
784
|
-
```
|
|
785
|
-
|
|
786
|
-
### Clojure: fnil によるデフォルト値関数
|
|
787
|
-
|
|
788
|
-
Clojure の `fnil` は、nil が渡された場合にデフォルト値を使う関数を生成します:
|
|
789
|
-
|
|
790
|
-
```clojure
|
|
791
|
-
(def safe-inc (fnil inc 0))
|
|
792
|
-
(safe-inc nil) ; => 1
|
|
793
|
-
(safe-inc 5) ; => 6
|
|
794
|
-
```
|
|
795
|
-
|
|
796
|
-
### Java: sealed interface(Java 17+)
|
|
797
|
-
|
|
798
|
-
Java 17 の `sealed interface` は、実装クラスを限定した直和型を実現します:
|
|
799
|
-
|
|
800
|
-
```java
|
|
801
|
-
public sealed interface YearsActive permits StillActive, ActiveBetween {}
|
|
802
|
-
public record StillActive(int since) implements YearsActive {}
|
|
803
|
-
public record ActiveBetween(int start, int end) implements YearsActive {}
|
|
804
|
-
```
|
|
805
|
-
|
|
806
|
-
Java 21 のパターンマッチ switch と組み合わせると、Scala に近い ADT 操作が可能になります。
|
|
807
|
-
|
|
808
|
-
---
|
|
809
|
-
|
|
810
|
-
## 7.10 実践的な選択指針
|
|
811
|
-
|
|
812
|
-
### Either/Result の選択
|
|
813
|
-
|
|
814
|
-
| 要件 | 推奨言語 | 理由 |
|
|
815
|
-
|------|---------|------|
|
|
816
|
-
| 最も簡潔なエラー伝播 | Rust | `?` 演算子 + カスタムエラー enum |
|
|
817
|
-
| 可読性の高い合成 | Scala, C# | for 内包表記 / LINQ |
|
|
818
|
-
| 完全な型安全性 | Haskell | Either モナド + do 記法 |
|
|
819
|
-
| 既存 OOP 資産との共存 | Java + Vavr, C# + LE | ライブラリで段階導入 |
|
|
820
|
-
| エコシステム統一 | Elixir | {:ok}/{:error} がエコシステム全体で統一 |
|
|
821
|
-
|
|
822
|
-
### ADT の選択
|
|
823
|
-
|
|
824
|
-
| 要件 | 推奨言語 | 理由 |
|
|
825
|
-
|------|---------|------|
|
|
826
|
-
| 網羅性チェックの強制 | Rust | match の網羅性がコンパイルエラー |
|
|
827
|
-
| 最も表現力の高い ADT | Haskell, F# | ファーストクラスの直和型 |
|
|
828
|
-
| OOP チームでの導入 | Scala, Java, C# | sealed trait/interface でなじみやすい |
|
|
829
|
-
| 型レベルの Union | TypeScript | discriminated union |
|
|
830
|
-
|
|
831
|
-
---
|
|
832
|
-
|
|
833
|
-
## 7.11 まとめ
|
|
834
|
-
|
|
835
|
-
本章では、11 言語での Either/Result と ADT の実装を比較し、以下を確認しました:
|
|
836
|
-
|
|
837
|
-
**共通の原則**:
|
|
838
|
-
|
|
839
|
-
- Either = Right(成功) | Left(失敗) は全言語で同じ構造
|
|
840
|
-
- ADT = 直和型 + 直積型でドメインを正確にモデリング
|
|
841
|
-
- パターンマッチによる各ケースの安全な処理
|
|
842
|
-
|
|
843
|
-
**言語間の差異**:
|
|
844
|
-
|
|
845
|
-
- 命名は 3 系統(Either 系 / Result 系 / Success/Failure 系)
|
|
846
|
-
- ADT の表現力は 4 段階(ファーストクラス → 型で近似 → 慣習的 → データ表現)
|
|
847
|
-
- 網羅性チェックは Rust が最も厳格(コンパイルエラー)
|
|
848
|
-
|
|
849
|
-
**学び**:
|
|
850
|
-
|
|
851
|
-
- Either は Option の「失敗に理由を持たせた」拡張
|
|
852
|
-
- 合成構文(for / do / LINQ / `?`)は Option と Either で共通
|
|
853
|
-
- ADT + パターンマッチは、不正な状態を型レベルで排除する強力なツール
|
|
854
|
-
|
|
855
|
-
---
|
|
856
|
-
|
|
857
|
-
### 各言語の詳細記事
|
|
858
|
-
|
|
859
|
-
| 言語 | 記事リンク |
|
|
860
|
-
|------|-----------|
|
|
861
|
-
| Scala | [Part III: エラーハンドリング](../scala/part-3.md) |
|
|
862
|
-
| Java | [Part III: エラーハンドリング](../java/part-3.md) |
|
|
863
|
-
| F# | [Part III: エラーハンドリング](../fsharp/part-3.md) |
|
|
864
|
-
| C# | [Part III: エラーハンドリング](../csharp/part-3.md) |
|
|
865
|
-
| Haskell | [Part III: エラーハンドリング](../haskell/part-3.md) |
|
|
866
|
-
| Clojure | [Part III: エラーハンドリング](../clojure/part-3.md) |
|
|
867
|
-
| Elixir | [Part III: エラーハンドリング](../elixir/part-3.md) |
|
|
868
|
-
| Rust | [Part III: エラーハンドリング](../rust/part-3.md) |
|
|
869
|
-
| Python | [Part III: エラーハンドリング](../python/part-3.md) |
|
|
870
|
-
| TypeScript | [Part III: エラーハンドリング](../typescript/part-3.md) |
|
|
871
|
-
| Ruby | [Part III: エラーハンドリング](../ruby/part-3.md) |
|
|
1
|
+
# Part III - 第 7 章:Either 型と代数的データ型
|
|
2
|
+
|
|
3
|
+
## 7.1 はじめに:Option の限界
|
|
4
|
+
|
|
5
|
+
前章で学んだ Option 型は、値の有無を型で表現する強力な手段でした。しかし、`None` は「なぜ失敗したか」の情報を持ちません。Either/Result 型は、失敗の理由をエラー値として保持し、より豊かなエラーハンドリングを実現します。
|
|
6
|
+
|
|
7
|
+
さらに本章では、**代数的データ型**(ADT: Algebraic Data Type)を学びます。ADT は「直和型」と「直積型」の組み合わせで、ドメインの概念を正確にモデリングする関数型プログラミングの基盤です。
|
|
8
|
+
|
|
9
|
+
本章では、11 言語での Either/Result と ADT の実装を横断的に比較し、以下を明らかにします:
|
|
10
|
+
|
|
11
|
+
- Either/Result の実装方式の違い(組み込み vs ライブラリ vs タプル/マップ)
|
|
12
|
+
- ADT の表現方法(sealed trait, enum, 判別共用体, discriminated union)
|
|
13
|
+
- パターンマッチの網羅性チェックの言語間差異
|
|
14
|
+
|
|
15
|
+
```plantuml
|
|
16
|
+
@startuml
|
|
17
|
+
!theme plain
|
|
18
|
+
|
|
19
|
+
rectangle "Option" #LightYellow {
|
|
20
|
+
card "Some(value)" as os
|
|
21
|
+
card "None(理由なし)" as on
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
rectangle "Either / Result" #LightGreen {
|
|
25
|
+
card "Right(value) / Ok(value)" as er
|
|
26
|
+
card "Left(error) / Err(error)" as el
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
rectangle "ADT" #LightBlue {
|
|
30
|
+
card "直和型(Sum Type)\nA | B | C" as sum
|
|
31
|
+
card "直積型(Product Type)\nA × B × C" as prod
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
on -right-> el : "失敗の理由を追加"
|
|
35
|
+
|
|
36
|
+
@enduml
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 7.2 共通の本質:Either = Right | Left
|
|
42
|
+
|
|
43
|
+
11 言語すべてに共通する Either/Result の構造は、**成功と失敗の 2 つのケース**を持つ型です:
|
|
44
|
+
|
|
45
|
+
1. **Right / Ok / Success**: 処理が成功し、値を保持する
|
|
46
|
+
2. **Left / Err / Failure**: 処理が失敗し、エラー情報を保持する
|
|
47
|
+
|
|
48
|
+
3 つの言語グループから代表例を見てみましょう:
|
|
49
|
+
|
|
50
|
+
```haskell
|
|
51
|
+
-- Haskell: Either 型(言語組み込み)
|
|
52
|
+
data Either e a = Left e | Right a
|
|
53
|
+
|
|
54
|
+
-- 使用例
|
|
55
|
+
extractName :: String -> Either String String
|
|
56
|
+
extractName rawShow =
|
|
57
|
+
case elemIndex '(' rawShow of
|
|
58
|
+
Just idx | idx > 0 -> Right $ trim $ take idx rawShow
|
|
59
|
+
_ -> Left $ "Can't extract name from " ++ rawShow
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```rust
|
|
63
|
+
// Rust: Result 型(言語組み込み)
|
|
64
|
+
pub fn extract_name(raw_show: &str) -> Result<String, String> {
|
|
65
|
+
let bracket_open = raw_show
|
|
66
|
+
.find('(')
|
|
67
|
+
.ok_or_else(|| format!("Can't find '(' in {}", raw_show))?;
|
|
68
|
+
|
|
69
|
+
if bracket_open > 0 {
|
|
70
|
+
Ok(raw_show[..bracket_open].trim().to_string())
|
|
71
|
+
} else {
|
|
72
|
+
Err(format!("Can't extract name from {}", raw_show))
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```scala
|
|
78
|
+
// Scala: Either 型(標準ライブラリ)
|
|
79
|
+
def extractName(show: String): Either[String, String] = {
|
|
80
|
+
val bracketOpen = show.indexOf('(')
|
|
81
|
+
if (bracketOpen > 0) Right(show.substring(0, bracketOpen).trim)
|
|
82
|
+
else Left(s"Can't extract name from $show")
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 7.3 Either/Result の実装方式
|
|
89
|
+
|
|
90
|
+
### アプローチ 1: 言語組み込み
|
|
91
|
+
|
|
92
|
+
| 言語 | 型名 | 成功 | 失敗 | 特徴 |
|
|
93
|
+
|------|------|------|------|------|
|
|
94
|
+
| **Haskell** | `Either e a` | `Right a` | `Left e` | 最も古典的な Either |
|
|
95
|
+
| **Rust** | `Result<T, E>` | `Ok(T)` | `Err(E)` | `?` 演算子で簡潔な伝播 |
|
|
96
|
+
| **F#** | `Result<'T, 'E>` | `Ok value` | `Error e` | パイプ + パターンマッチ |
|
|
97
|
+
|
|
98
|
+
### アプローチ 2: ライブラリ提供
|
|
99
|
+
|
|
100
|
+
| 言語 | ライブラリ | 型名 | 成功 | 失敗 |
|
|
101
|
+
|------|-----------|------|------|------|
|
|
102
|
+
| **Scala** | 標準ライブラリ | `Either[E, A]` | `Right(a)` | `Left(e)` |
|
|
103
|
+
| **Java** | Vavr | `Either<L, R>` | `Either.right(r)` | `Either.left(l)` |
|
|
104
|
+
| **C#** | LanguageExt | `Either<L, R>` | `Right(r)` | `Left(l)` |
|
|
105
|
+
| **TypeScript** | fp-ts | `Either<E, A>` | `E.right(a)` | `E.left(e)` |
|
|
106
|
+
| **Python** | returns | `Result[T, E]` | `Success(t)` | `Failure(e)` |
|
|
107
|
+
| **Ruby** | dry-monads | `Result` | `Success(t)` | `Failure(e)` |
|
|
108
|
+
|
|
109
|
+
### アプローチ 3: タプル / マップベース
|
|
110
|
+
|
|
111
|
+
| 言語 | 構造 | 成功 | 失敗 |
|
|
112
|
+
|------|------|------|------|
|
|
113
|
+
| **Elixir** | タプル | `{:ok, value}` | `{:error, reason}` |
|
|
114
|
+
| **Clojure** | マップ | `{:status :ok, :value v}` | `{:status :error, :error msg}` |
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 7.4 TV 番組パース:Either による合成
|
|
119
|
+
|
|
120
|
+
Option 版と同じ TV 番組パースを Either で実装し、**失敗の理由**が伝播する様子を比較します。
|
|
121
|
+
|
|
122
|
+
### 代表 3 言語の比較
|
|
123
|
+
|
|
124
|
+
**Haskell**: do 記法
|
|
125
|
+
|
|
126
|
+
```haskell
|
|
127
|
+
parseShowE :: String -> Either String TvShow
|
|
128
|
+
parseShowE rawShow = do
|
|
129
|
+
name <- extractNameE rawShow
|
|
130
|
+
yearStart <- extractYearStartE rawShow `orElseE` extractSingleYearE rawShow
|
|
131
|
+
yearEnd <- extractYearEndE rawShow `orElseE` extractSingleYearE rawShow
|
|
132
|
+
return $ TvShow name yearStart yearEnd
|
|
133
|
+
|
|
134
|
+
-- 失敗例
|
|
135
|
+
parseShowE "Invalid"
|
|
136
|
+
-- Left "Can't extract name from Invalid"(失敗の理由が残る)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Scala**: for 内包表記
|
|
140
|
+
|
|
141
|
+
```scala
|
|
142
|
+
def parseShow(rawShow: String): Either[String, TvShow] =
|
|
143
|
+
for {
|
|
144
|
+
name <- extractName(rawShow)
|
|
145
|
+
yearStart <- extractYearStart(rawShow).orElse(extractSingleYear(rawShow))
|
|
146
|
+
yearEnd <- extractYearEnd(rawShow).orElse(extractSingleYear(rawShow))
|
|
147
|
+
} yield TvShow(name, yearStart, yearEnd)
|
|
148
|
+
|
|
149
|
+
// 失敗例
|
|
150
|
+
parseShow("Invalid")
|
|
151
|
+
// Left("Can't extract name from Invalid")
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Rust**: ? 演算子
|
|
155
|
+
|
|
156
|
+
```rust
|
|
157
|
+
pub fn parse_show(raw_show: &str) -> Result<TvShow, String> {
|
|
158
|
+
let name = extract_name(raw_show)?;
|
|
159
|
+
let year_start = extract_year_start(raw_show)
|
|
160
|
+
.or_else(|_| extract_single_year(raw_show))?;
|
|
161
|
+
let year_end = extract_year_end(raw_show)
|
|
162
|
+
.or_else(|_| extract_single_year(raw_show))?;
|
|
163
|
+
|
|
164
|
+
Ok(TvShow::new(&name, year_start, year_end))
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 失敗例
|
|
168
|
+
parse_show("Invalid")
|
|
169
|
+
// Err("Can't extract name from Invalid")
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 全 11 言語の実装
|
|
173
|
+
|
|
174
|
+
#### 関数型ファースト言語
|
|
175
|
+
|
|
176
|
+
<details>
|
|
177
|
+
<summary>Haskell 実装</summary>
|
|
178
|
+
|
|
179
|
+
```haskell
|
|
180
|
+
parseShowE :: String -> Either String TvShow
|
|
181
|
+
parseShowE rawShow = do
|
|
182
|
+
name <- extractNameE rawShow
|
|
183
|
+
yearStart <- extractYearStartE rawShow `orElseE` extractSingleYearE rawShow
|
|
184
|
+
yearEnd <- extractYearEndE rawShow `orElseE` extractSingleYearE rawShow
|
|
185
|
+
return $ TvShow name yearStart yearEnd
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Haskell の `Either` は `Monad` インスタンスを持ち、do 記法で `Maybe` と同じように合成できます。
|
|
189
|
+
|
|
190
|
+
</details>
|
|
191
|
+
|
|
192
|
+
<details>
|
|
193
|
+
<summary>Clojure 実装</summary>
|
|
194
|
+
|
|
195
|
+
```clojure
|
|
196
|
+
(defn ok [value] {:status :ok :value value})
|
|
197
|
+
(defn error [message] {:status :error :error message})
|
|
198
|
+
|
|
199
|
+
(defn result-flatmap [f result]
|
|
200
|
+
(if (= (:status result) :ok)
|
|
201
|
+
(f (:value result))
|
|
202
|
+
result))
|
|
203
|
+
|
|
204
|
+
(defn parse-show-result [raw-show]
|
|
205
|
+
(result-flatmap
|
|
206
|
+
(fn [name]
|
|
207
|
+
(let [year-start (result-or-else
|
|
208
|
+
(extract-year-start-result raw-show)
|
|
209
|
+
#(extract-single-year-result raw-show))
|
|
210
|
+
year-end (result-or-else
|
|
211
|
+
(extract-year-end-result raw-show)
|
|
212
|
+
#(extract-single-year-result raw-show))]
|
|
213
|
+
(result-flatmap
|
|
214
|
+
(fn [ys]
|
|
215
|
+
(result-flatmap
|
|
216
|
+
(fn [ye] (ok {:title name :start ys :end ye}))
|
|
217
|
+
year-end))
|
|
218
|
+
year-start)))
|
|
219
|
+
(extract-name-result raw-show)))
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Clojure では専用の型を持たないため、マップベースの Result パターンと `result-flatmap` 関数を手動で実装します。
|
|
223
|
+
|
|
224
|
+
</details>
|
|
225
|
+
|
|
226
|
+
<details>
|
|
227
|
+
<summary>Elixir 実装</summary>
|
|
228
|
+
|
|
229
|
+
```elixir
|
|
230
|
+
def parse_show(raw_show) do
|
|
231
|
+
with {:ok, name} <- extract_name(raw_show),
|
|
232
|
+
{:ok, year_start} <- or_else(extract_year_start(raw_show),
|
|
233
|
+
fn -> extract_single_year(raw_show) end),
|
|
234
|
+
{:ok, year_end} <- or_else(extract_year_end(raw_show),
|
|
235
|
+
fn -> extract_single_year(raw_show) end) do
|
|
236
|
+
{:ok, %TvShow{title: name, start: year_start, end_year: year_end}}
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Elixir の `with` 式は、パターンマッチが失敗すると最初の不一致を返します。`{:ok, value}` / `{:error, reason}` のタプルパターンは Erlang/OTP の伝統です。
|
|
242
|
+
|
|
243
|
+
</details>
|
|
244
|
+
|
|
245
|
+
<details>
|
|
246
|
+
<summary>F# 実装</summary>
|
|
247
|
+
|
|
248
|
+
```fsharp
|
|
249
|
+
let parseShow (rawShow: string) : Result<TvShow, string> =
|
|
250
|
+
match extractName rawShow with
|
|
251
|
+
| Error e -> Error e
|
|
252
|
+
| Ok name ->
|
|
253
|
+
let yearStart =
|
|
254
|
+
extractYearStart rawShow
|
|
255
|
+
|> Result.orElse (extractSingleYear rawShow)
|
|
256
|
+
let yearEnd =
|
|
257
|
+
extractYearEnd rawShow
|
|
258
|
+
|> Result.orElse (extractSingleYear rawShow)
|
|
259
|
+
match yearStart, yearEnd with
|
|
260
|
+
| Ok start, Ok endYear ->
|
|
261
|
+
Ok { Title = name; Start = start; End = endYear }
|
|
262
|
+
| Error e, _ -> Error e
|
|
263
|
+
| _, Error e -> Error e
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
F# ではパターンマッチで `Ok` / `Error` を明示的に処理します。
|
|
267
|
+
|
|
268
|
+
</details>
|
|
269
|
+
|
|
270
|
+
#### マルチパラダイム言語
|
|
271
|
+
|
|
272
|
+
<details>
|
|
273
|
+
<summary>Scala 実装</summary>
|
|
274
|
+
|
|
275
|
+
```scala
|
|
276
|
+
def parseShow(rawShow: String): Either[String, TvShow] =
|
|
277
|
+
for {
|
|
278
|
+
name <- extractName(rawShow)
|
|
279
|
+
yearStart <- extractYearStart(rawShow).orElse(extractSingleYear(rawShow))
|
|
280
|
+
yearEnd <- extractYearEnd(rawShow).orElse(extractSingleYear(rawShow))
|
|
281
|
+
} yield TvShow(name, yearStart, yearEnd)
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
</details>
|
|
285
|
+
|
|
286
|
+
<details>
|
|
287
|
+
<summary>Rust 実装</summary>
|
|
288
|
+
|
|
289
|
+
```rust
|
|
290
|
+
pub fn parse_show(raw_show: &str) -> Result<TvShow, String> {
|
|
291
|
+
let name = extract_name(raw_show)?;
|
|
292
|
+
let year_start = extract_year_start(raw_show)
|
|
293
|
+
.or_else(|_| extract_single_year(raw_show))?;
|
|
294
|
+
let year_end = extract_year_end(raw_show)
|
|
295
|
+
.or_else(|_| extract_single_year(raw_show))?;
|
|
296
|
+
|
|
297
|
+
Ok(TvShow::new(&name, year_start, year_end))
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Rust の `?` 演算子は `Option` と `Result` の両方で使えます。`or_else(|_| ...)` のクロージャ引数 `_` はエラー値を無視することを示します。
|
|
302
|
+
|
|
303
|
+
</details>
|
|
304
|
+
|
|
305
|
+
<details>
|
|
306
|
+
<summary>TypeScript (fp-ts) 実装</summary>
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
import * as E from 'fp-ts/Either'
|
|
310
|
+
|
|
311
|
+
const parseShow = (rawShow: string): E.Either<string, TvShow> =>
|
|
312
|
+
pipe(
|
|
313
|
+
E.Do,
|
|
314
|
+
E.bind('name', () => extractName(rawShow)),
|
|
315
|
+
E.bind('start', () =>
|
|
316
|
+
pipe(
|
|
317
|
+
extractYearStart(rawShow),
|
|
318
|
+
E.orElse(() => extractSingleYear(rawShow))
|
|
319
|
+
)
|
|
320
|
+
),
|
|
321
|
+
E.bind('end', () =>
|
|
322
|
+
pipe(
|
|
323
|
+
extractYearEnd(rawShow),
|
|
324
|
+
E.orElse(() => extractSingleYear(rawShow))
|
|
325
|
+
)
|
|
326
|
+
),
|
|
327
|
+
E.map(({ name, start, end }) => ({ title: name, start, end }))
|
|
328
|
+
)
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
</details>
|
|
332
|
+
|
|
333
|
+
#### OOP + FP ライブラリ言語
|
|
334
|
+
|
|
335
|
+
<details>
|
|
336
|
+
<summary>Java (Vavr) 実装</summary>
|
|
337
|
+
|
|
338
|
+
```java
|
|
339
|
+
public static Either<String, TvShow> parseShow(String rawShow) {
|
|
340
|
+
return extractName(rawShow).flatMap(name ->
|
|
341
|
+
extractYearStart(rawShow).orElse(() -> extractSingleYear(rawShow))
|
|
342
|
+
.flatMap(yearStart ->
|
|
343
|
+
extractYearEnd(rawShow).orElse(() -> extractSingleYear(rawShow))
|
|
344
|
+
.map(yearEnd -> new TvShow(name, yearStart, yearEnd))
|
|
345
|
+
)
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
</details>
|
|
351
|
+
|
|
352
|
+
<details>
|
|
353
|
+
<summary>C# (LanguageExt) 実装</summary>
|
|
354
|
+
|
|
355
|
+
```csharp
|
|
356
|
+
Either<string, TvShow> ParseShow(string rawShow) =>
|
|
357
|
+
from name in ExtractName(rawShow)
|
|
358
|
+
from yearStart in ExtractYearStart(rawShow) || ExtractSingleYear(rawShow)
|
|
359
|
+
from yearEnd in ExtractYearEnd(rawShow) || ExtractSingleYear(rawShow)
|
|
360
|
+
select new TvShow(name, yearStart, yearEnd);
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
C# の LINQ + `||` 演算子で Scala の for 内包表記に匹敵する簡潔さを実現しています。
|
|
364
|
+
|
|
365
|
+
</details>
|
|
366
|
+
|
|
367
|
+
<details>
|
|
368
|
+
<summary>Python (returns) 実装</summary>
|
|
369
|
+
|
|
370
|
+
```python
|
|
371
|
+
from returns.result import Result, Success, Failure
|
|
372
|
+
|
|
373
|
+
def parse_show(raw_show: str) -> Result[TvShow, str]:
|
|
374
|
+
name = extract_name_result(raw_show)
|
|
375
|
+
year_start = extract_year_start_result(raw_show).lash(
|
|
376
|
+
lambda _: extract_single_year_result(raw_show)
|
|
377
|
+
)
|
|
378
|
+
year_end = extract_year_end_result(raw_show).lash(
|
|
379
|
+
lambda _: extract_single_year_result(raw_show)
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
return name.bind(
|
|
383
|
+
lambda n: year_start.bind(
|
|
384
|
+
lambda s: year_end.map(lambda e: TvShow(n, s, e))
|
|
385
|
+
)
|
|
386
|
+
)
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
</details>
|
|
390
|
+
|
|
391
|
+
<details>
|
|
392
|
+
<summary>Ruby (dry-monads) 実装</summary>
|
|
393
|
+
|
|
394
|
+
```ruby
|
|
395
|
+
def parse_show(raw_show)
|
|
396
|
+
name = extract_name(raw_show)
|
|
397
|
+
year_start = extract_year_start(raw_show).or(extract_single_year(raw_show))
|
|
398
|
+
year_end = extract_year_end(raw_show).or(extract_single_year(raw_show))
|
|
399
|
+
|
|
400
|
+
name.bind do |n|
|
|
401
|
+
year_start.bind do |ys|
|
|
402
|
+
year_end.fmap do |ye|
|
|
403
|
+
TvShow.new(title: n, start_year: ys, end_year: ye)
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
</details>
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## 7.5 代数的データ型(ADT)
|
|
415
|
+
|
|
416
|
+
ADT は関数型プログラミングのドメインモデリングの基盤です。**直和型**(「A または B」)と**直積型**(「A かつ B」)の組み合わせで、ドメインの概念を型で正確に表現します。
|
|
417
|
+
|
|
418
|
+
### 直和型の例:YearsActive
|
|
419
|
+
|
|
420
|
+
アーティストの活動期間は「活動中」か「活動終了」のどちらかです:
|
|
421
|
+
|
|
422
|
+
```plantuml
|
|
423
|
+
@startuml
|
|
424
|
+
!theme plain
|
|
425
|
+
|
|
426
|
+
rectangle "YearsActive(直和型)" #LightBlue {
|
|
427
|
+
card "StillActive(since: Int)" as sa #LightGreen
|
|
428
|
+
card "ActiveBetween(start: Int, end: Int)" as ab #LightYellow
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
note bottom of sa : 現在も活動中
|
|
432
|
+
note bottom of ab : 活動を終了
|
|
433
|
+
|
|
434
|
+
@enduml
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### 代表 3 言語の ADT 定義
|
|
438
|
+
|
|
439
|
+
**Haskell**: data 型
|
|
440
|
+
|
|
441
|
+
```haskell
|
|
442
|
+
data MusicGenre = HeavyMetal | Pop | HardRock | Grunge
|
|
443
|
+
deriving (Show, Eq)
|
|
444
|
+
|
|
445
|
+
data YearsActive
|
|
446
|
+
= StillActive Int
|
|
447
|
+
| ActiveBetween Int Int
|
|
448
|
+
deriving (Show, Eq)
|
|
449
|
+
|
|
450
|
+
data Artist = Artist
|
|
451
|
+
{ artistName :: String
|
|
452
|
+
, artistGenre :: MusicGenre
|
|
453
|
+
, artistOrigin :: Location
|
|
454
|
+
, artistYearsActive :: YearsActive
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**Rust**: enum
|
|
459
|
+
|
|
460
|
+
```rust
|
|
461
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
462
|
+
pub enum MusicGenre {
|
|
463
|
+
HeavyMetal,
|
|
464
|
+
Pop,
|
|
465
|
+
HardRock,
|
|
466
|
+
Jazz,
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
470
|
+
pub enum YearsActive {
|
|
471
|
+
StillActive { since: i32 },
|
|
472
|
+
ActiveBetween { start: i32, end: i32 },
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
pub struct Artist {
|
|
476
|
+
pub name: String,
|
|
477
|
+
pub genre: MusicGenre,
|
|
478
|
+
pub origin: Location,
|
|
479
|
+
pub years_active: YearsActive,
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
**Scala**: enum(Scala 3)
|
|
484
|
+
|
|
485
|
+
```scala
|
|
486
|
+
enum MusicGenre {
|
|
487
|
+
case HeavyMetal, Pop, HardRock
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
enum YearsActive {
|
|
491
|
+
case StillActive(since: Int)
|
|
492
|
+
case ActiveBetween(start: Int, end: Int)
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
case class Artist(
|
|
496
|
+
name: String,
|
|
497
|
+
genre: MusicGenre,
|
|
498
|
+
origin: Location,
|
|
499
|
+
yearsActive: YearsActive
|
|
500
|
+
)
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
### 全 11 言語の ADT 表現
|
|
504
|
+
|
|
505
|
+
| 言語 | 直和型の構文 | 直積型の構文 | 網羅性チェック |
|
|
506
|
+
|------|------------|------------|-------------|
|
|
507
|
+
| **Haskell** | `data T = A \| B` | `data T = T { field :: Type }` | コンパイラ警告 |
|
|
508
|
+
| **Rust** | `enum T { A, B }` | `struct T { field: Type }` | コンパイルエラー |
|
|
509
|
+
| **F#** | `type T = A \| B` | `type T = { Field: Type }` | コンパイラ警告 |
|
|
510
|
+
| **Scala** | `enum T { case A; case B }` | `case class T(field: Type)` | コンパイラ警告 |
|
|
511
|
+
| **Java** | `sealed interface T` + `record` | `record T(Type field)` | コンパイルエラー(21+) |
|
|
512
|
+
| **C#** | `abstract record` + 派生 record | `record T(Type Field)` | switch 式で警告 |
|
|
513
|
+
| **TypeScript** | `type T = { _tag: 'A' } \| { _tag: 'B' }` | `interface T { field: Type }` | なし(型レベル) |
|
|
514
|
+
| **Python** | `Enum` + `@dataclass` | `@dataclass(frozen=True)` | match(3.10+) |
|
|
515
|
+
| **Clojure** | マップ + `:type` タグ | マップ | なし |
|
|
516
|
+
| **Elixir** | タプル `{:tag, ...}` | `defstruct` | なし |
|
|
517
|
+
| **Ruby** | モジュール + クラス | `Struct` | case when |
|
|
518
|
+
|
|
519
|
+
<details>
|
|
520
|
+
<summary>全 11 言語の ADT 定義</summary>
|
|
521
|
+
|
|
522
|
+
**F#**(判別共用体):
|
|
523
|
+
```fsharp
|
|
524
|
+
type MusicGenre = HeavyMetal | Pop | HardRock | Jazz
|
|
525
|
+
|
|
526
|
+
type YearsActive =
|
|
527
|
+
| StillActive of since: int
|
|
528
|
+
| ActiveBetween of start: int * endYear: int
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
**Java**(sealed interface + record):
|
|
532
|
+
```java
|
|
533
|
+
public sealed interface YearsActive permits StillActive, ActiveBetween {}
|
|
534
|
+
public record StillActive(int since) implements YearsActive {}
|
|
535
|
+
public record ActiveBetween(int start, int end) implements YearsActive {}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
**C#**(abstract record):
|
|
539
|
+
```csharp
|
|
540
|
+
public abstract record YearsActive;
|
|
541
|
+
public record StillActive(int Since) : YearsActive;
|
|
542
|
+
public record ActiveBetween(int Start, int EndYear) : YearsActive;
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
**TypeScript**(discriminated union):
|
|
546
|
+
```typescript
|
|
547
|
+
type YearsActive =
|
|
548
|
+
| { readonly _tag: 'StillActive'; readonly since: number }
|
|
549
|
+
| { readonly _tag: 'ActiveBetween'; readonly start: number; readonly end: number }
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
**Clojure**(マップ + タグ):
|
|
553
|
+
```clojure
|
|
554
|
+
(defn still-active [since]
|
|
555
|
+
{:type :still-active :since since})
|
|
556
|
+
|
|
557
|
+
(defn active-between [start end]
|
|
558
|
+
{:type :active-between :start start :end end})
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
**Elixir**(タプル):
|
|
562
|
+
```elixir
|
|
563
|
+
# {:still_active, since}
|
|
564
|
+
# {:active_between, start, end_year}
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**Python**(dataclass + Union):
|
|
568
|
+
```python
|
|
569
|
+
@dataclass(frozen=True)
|
|
570
|
+
class StillActive:
|
|
571
|
+
since: int
|
|
572
|
+
|
|
573
|
+
@dataclass(frozen=True)
|
|
574
|
+
class ActiveBetween:
|
|
575
|
+
start: int
|
|
576
|
+
end: int
|
|
577
|
+
|
|
578
|
+
YearsActive = StillActive | ActiveBetween
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
**Ruby**(Module + Classes):
|
|
582
|
+
```ruby
|
|
583
|
+
module YearsActive
|
|
584
|
+
class StillActive
|
|
585
|
+
attr_reader :since
|
|
586
|
+
def initialize(since) = @since = since
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
class ActiveBetween
|
|
590
|
+
attr_reader :start_year, :end_year
|
|
591
|
+
def initialize(start_year, end_year)
|
|
592
|
+
@start_year = start_year
|
|
593
|
+
@end_year = end_year
|
|
594
|
+
end
|
|
595
|
+
end
|
|
596
|
+
end
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
</details>
|
|
600
|
+
|
|
601
|
+
---
|
|
602
|
+
|
|
603
|
+
## 7.6 パターンマッチ:ADT の安全な処理
|
|
604
|
+
|
|
605
|
+
ADT の各ケースを処理するパターンマッチは、関数型プログラミングの中核です。アーティストが特定期間に活動していたかを判定する関数で比較します。
|
|
606
|
+
|
|
607
|
+
### 代表 3 言語の比較
|
|
608
|
+
|
|
609
|
+
**Haskell**:
|
|
610
|
+
|
|
611
|
+
```haskell
|
|
612
|
+
wasArtistActive :: Artist -> Int -> Int -> Bool
|
|
613
|
+
wasArtistActive artist yearStart yearEnd =
|
|
614
|
+
case artistYearsActive artist of
|
|
615
|
+
StillActive since -> since <= yearEnd
|
|
616
|
+
ActiveBetween start end_ -> start <= yearEnd && end_ >= yearStart
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
**Rust**:
|
|
620
|
+
|
|
621
|
+
```rust
|
|
622
|
+
pub fn was_artist_active(artist: &Artist, year_start: i32, year_end: i32) -> bool {
|
|
623
|
+
match &artist.years_active {
|
|
624
|
+
YearsActive::StillActive { since } => *since <= year_end,
|
|
625
|
+
YearsActive::ActiveBetween { start, end } =>
|
|
626
|
+
*start <= year_end && *end >= year_start,
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
**Scala**:
|
|
632
|
+
|
|
633
|
+
```scala
|
|
634
|
+
def wasArtistActive(artist: Artist, yearStart: Int, yearEnd: Int): Boolean =
|
|
635
|
+
artist.yearsActive match {
|
|
636
|
+
case StillActive(since) => since <= yearEnd
|
|
637
|
+
case ActiveBetween(start, end) => start <= yearEnd && end >= yearStart
|
|
638
|
+
}
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
### 網羅性チェックの比較
|
|
642
|
+
|
|
643
|
+
| レベル | 言語 | 挙動 |
|
|
644
|
+
|--------|------|------|
|
|
645
|
+
| **コンパイルエラー** | Rust, Java (21+ sealed) | ケースが不足するとコンパイルが失敗する |
|
|
646
|
+
| **コンパイラ警告** | Haskell, Scala, F# | 警告が出るが、コンパイルは通る |
|
|
647
|
+
| **IDE 警告のみ** | C#, TypeScript | エディタが警告するが言語レベルでは強制しない |
|
|
648
|
+
| **なし** | Clojure, Elixir, Python, Ruby | 動的型付けのため網羅性チェックなし |
|
|
649
|
+
|
|
650
|
+
**発見**: Rust は `match` で全ケースを処理しないとコンパイルエラーになる唯一の言語です。これにより、ADT にケースを追加した際に、処理漏れを確実に検出できます。
|
|
651
|
+
|
|
652
|
+
---
|
|
653
|
+
|
|
654
|
+
## 7.7 Option と Either の変換
|
|
655
|
+
|
|
656
|
+
Option と Either は相互に変換可能です。失敗理由を付加して Option → Either、理由を捨てて Either → Option に変換します。
|
|
657
|
+
|
|
658
|
+
### 代表的な変換パターン
|
|
659
|
+
|
|
660
|
+
| 方向 | Scala | Haskell | Rust | F# |
|
|
661
|
+
|------|-------|---------|------|----|
|
|
662
|
+
| Option → Either | `opt.toRight("error")` | `maybeToEither "error" mb` | `opt.ok_or("error")` | `Option.toResult` |
|
|
663
|
+
| Either → Option | `either.toOption` | `eitherToMaybe e` | `result.ok()` | `Result.toOption` |
|
|
664
|
+
|
|
665
|
+
```scala
|
|
666
|
+
// Scala
|
|
667
|
+
val opt: Option[Int] = Some(42)
|
|
668
|
+
val either: Either[String, Int] = opt.toRight("Value not found")
|
|
669
|
+
// Right(42)
|
|
670
|
+
|
|
671
|
+
val back: Option[Int] = either.toOption
|
|
672
|
+
// Some(42)
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
```rust
|
|
676
|
+
// Rust
|
|
677
|
+
let opt: Option<i32> = Some(42);
|
|
678
|
+
let result: Result<i32, &str> = opt.ok_or("Value not found");
|
|
679
|
+
// Ok(42)
|
|
680
|
+
|
|
681
|
+
let back: Option<i32> = result.ok();
|
|
682
|
+
// Some(42)
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
---
|
|
686
|
+
|
|
687
|
+
## 7.8 比較分析:3 つの発見
|
|
688
|
+
|
|
689
|
+
### 発見 1: Either/Result の命名は 3 系統に分かれる
|
|
690
|
+
|
|
691
|
+
| 系統 | 成功 | 失敗 | 言語 |
|
|
692
|
+
|------|------|------|------|
|
|
693
|
+
| **Either 系** | `Right` | `Left` | Haskell, Scala, Java (Vavr), C# (LE), TypeScript (fp-ts) |
|
|
694
|
+
| **Result 系** | `Ok` | `Err` / `Error` | Rust, F# |
|
|
695
|
+
| **Success/Failure 系** | `Success` | `Failure` | Python (returns), Ruby (dry-monads) |
|
|
696
|
+
|
|
697
|
+
Either 系は数学的な「左右」に由来し、Result 系は実用的な命名です。Elixir の `{:ok, value}` / `{:error, reason}` は Result 系のタプル表現です。
|
|
698
|
+
|
|
699
|
+
### 発見 2: ADT の表現力は言語の型システムに依存する
|
|
700
|
+
|
|
701
|
+
```plantuml
|
|
702
|
+
@startuml
|
|
703
|
+
!theme plain
|
|
704
|
+
left to right direction
|
|
705
|
+
|
|
706
|
+
rectangle "Level 1: ファーストクラス ADT" #LightGreen {
|
|
707
|
+
card "Haskell (data)" as h
|
|
708
|
+
card "Rust (enum)" as rs
|
|
709
|
+
card "F# (判別共用体)" as fs
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
rectangle "Level 2: 型システムで近似" #LightBlue {
|
|
713
|
+
card "Scala (enum)" as sc
|
|
714
|
+
card "Java (sealed)" as jv
|
|
715
|
+
card "C# (abstract record)" as cs
|
|
716
|
+
card "TypeScript (discriminated union)" as ts
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
rectangle "Level 3: 慣習的 ADT" #LightYellow {
|
|
720
|
+
card "Python (dataclass + Union)" as py
|
|
721
|
+
card "Ruby (Module + Class)" as rb
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
rectangle "Level 4: データで表現" #LightCoral {
|
|
725
|
+
card "Clojure (:type タグ)" as clj
|
|
726
|
+
card "Elixir (タプル)" as ex
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
@enduml
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
Haskell, Rust, F# はファーストクラスの ADT を持ち、コンパイラによる網羅性チェックが保証されます。TypeScript の discriminated union は `_tag` フィールドで近似しますが、言語レベルの保証はありません。
|
|
733
|
+
|
|
734
|
+
### 発見 3: Either の合成構文は Option と共通
|
|
735
|
+
|
|
736
|
+
前章の Option と本章の Either は、同じ合成構文(for / do / LINQ / `?`)で使えます。これは両者が同じ**モナドインターフェース**を共有しているからです:
|
|
737
|
+
|
|
738
|
+
```
|
|
739
|
+
Option.flatMap: Option[A] → (A → Option[B]) → Option[B]
|
|
740
|
+
Either.flatMap: Either[E,A] → (A → Either[E,B]) → Either[E,B]
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
Scala の for 内包表記、Haskell の do 記法、Rust の `?` 演算子は、Option と Either の両方で同じように機能します。
|
|
744
|
+
|
|
745
|
+
---
|
|
746
|
+
|
|
747
|
+
## 7.9 言語固有の特徴
|
|
748
|
+
|
|
749
|
+
### Rust: カスタムエラー型と ? 演算子
|
|
750
|
+
|
|
751
|
+
Rust では文字列ではなく専用の enum でエラーを表現するのが慣習です:
|
|
752
|
+
|
|
753
|
+
```rust
|
|
754
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
755
|
+
pub enum ParseError {
|
|
756
|
+
MissingName,
|
|
757
|
+
MissingYear,
|
|
758
|
+
InvalidYear(String),
|
|
759
|
+
MissingBracket,
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
pub fn extract_name(raw_show: &str) -> Result<String, ParseError> {
|
|
763
|
+
let bracket_open = raw_show.find('(').ok_or(ParseError::MissingBracket)?;
|
|
764
|
+
if bracket_open > 0 {
|
|
765
|
+
Ok(raw_show[..bracket_open].trim().to_string())
|
|
766
|
+
} else {
|
|
767
|
+
Err(ParseError::MissingName)
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
エラー型を enum にすることで、パターンマッチでエラーの種類ごとに処理を分けられます。
|
|
773
|
+
|
|
774
|
+
### Elixir: {:ok, value} / {:error, reason} のタプルパターン
|
|
775
|
+
|
|
776
|
+
Elixir のタプルパターンは Erlang/OTP の伝統を引き継ぎ、エコシステム全体で統一されています:
|
|
777
|
+
|
|
778
|
+
```elixir
|
|
779
|
+
case File.read("config.json") do
|
|
780
|
+
{:ok, content} -> Jason.decode(content)
|
|
781
|
+
{:error, :enoent} -> {:error, "File not found"}
|
|
782
|
+
{:error, reason} -> {:error, "Failed: #{reason}"}
|
|
783
|
+
end
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
### Clojure: fnil によるデフォルト値関数
|
|
787
|
+
|
|
788
|
+
Clojure の `fnil` は、nil が渡された場合にデフォルト値を使う関数を生成します:
|
|
789
|
+
|
|
790
|
+
```clojure
|
|
791
|
+
(def safe-inc (fnil inc 0))
|
|
792
|
+
(safe-inc nil) ; => 1
|
|
793
|
+
(safe-inc 5) ; => 6
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
### Java: sealed interface(Java 17+)
|
|
797
|
+
|
|
798
|
+
Java 17 の `sealed interface` は、実装クラスを限定した直和型を実現します:
|
|
799
|
+
|
|
800
|
+
```java
|
|
801
|
+
public sealed interface YearsActive permits StillActive, ActiveBetween {}
|
|
802
|
+
public record StillActive(int since) implements YearsActive {}
|
|
803
|
+
public record ActiveBetween(int start, int end) implements YearsActive {}
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
Java 21 のパターンマッチ switch と組み合わせると、Scala に近い ADT 操作が可能になります。
|
|
807
|
+
|
|
808
|
+
---
|
|
809
|
+
|
|
810
|
+
## 7.10 実践的な選択指針
|
|
811
|
+
|
|
812
|
+
### Either/Result の選択
|
|
813
|
+
|
|
814
|
+
| 要件 | 推奨言語 | 理由 |
|
|
815
|
+
|------|---------|------|
|
|
816
|
+
| 最も簡潔なエラー伝播 | Rust | `?` 演算子 + カスタムエラー enum |
|
|
817
|
+
| 可読性の高い合成 | Scala, C# | for 内包表記 / LINQ |
|
|
818
|
+
| 完全な型安全性 | Haskell | Either モナド + do 記法 |
|
|
819
|
+
| 既存 OOP 資産との共存 | Java + Vavr, C# + LE | ライブラリで段階導入 |
|
|
820
|
+
| エコシステム統一 | Elixir | {:ok}/{:error} がエコシステム全体で統一 |
|
|
821
|
+
|
|
822
|
+
### ADT の選択
|
|
823
|
+
|
|
824
|
+
| 要件 | 推奨言語 | 理由 |
|
|
825
|
+
|------|---------|------|
|
|
826
|
+
| 網羅性チェックの強制 | Rust | match の網羅性がコンパイルエラー |
|
|
827
|
+
| 最も表現力の高い ADT | Haskell, F# | ファーストクラスの直和型 |
|
|
828
|
+
| OOP チームでの導入 | Scala, Java, C# | sealed trait/interface でなじみやすい |
|
|
829
|
+
| 型レベルの Union | TypeScript | discriminated union |
|
|
830
|
+
|
|
831
|
+
---
|
|
832
|
+
|
|
833
|
+
## 7.11 まとめ
|
|
834
|
+
|
|
835
|
+
本章では、11 言語での Either/Result と ADT の実装を比較し、以下を確認しました:
|
|
836
|
+
|
|
837
|
+
**共通の原則**:
|
|
838
|
+
|
|
839
|
+
- Either = Right(成功) | Left(失敗) は全言語で同じ構造
|
|
840
|
+
- ADT = 直和型 + 直積型でドメインを正確にモデリング
|
|
841
|
+
- パターンマッチによる各ケースの安全な処理
|
|
842
|
+
|
|
843
|
+
**言語間の差異**:
|
|
844
|
+
|
|
845
|
+
- 命名は 3 系統(Either 系 / Result 系 / Success/Failure 系)
|
|
846
|
+
- ADT の表現力は 4 段階(ファーストクラス → 型で近似 → 慣習的 → データ表現)
|
|
847
|
+
- 網羅性チェックは Rust が最も厳格(コンパイルエラー)
|
|
848
|
+
|
|
849
|
+
**学び**:
|
|
850
|
+
|
|
851
|
+
- Either は Option の「失敗に理由を持たせた」拡張
|
|
852
|
+
- 合成構文(for / do / LINQ / `?`)は Option と Either で共通
|
|
853
|
+
- ADT + パターンマッチは、不正な状態を型レベルで排除する強力なツール
|
|
854
|
+
|
|
855
|
+
---
|
|
856
|
+
|
|
857
|
+
### 各言語の詳細記事
|
|
858
|
+
|
|
859
|
+
| 言語 | 記事リンク |
|
|
860
|
+
|------|-----------|
|
|
861
|
+
| Scala | [Part III: エラーハンドリング](../scala/part-3.md) |
|
|
862
|
+
| Java | [Part III: エラーハンドリング](../java/part-3.md) |
|
|
863
|
+
| F# | [Part III: エラーハンドリング](../fsharp/part-3.md) |
|
|
864
|
+
| C# | [Part III: エラーハンドリング](../csharp/part-3.md) |
|
|
865
|
+
| Haskell | [Part III: エラーハンドリング](../haskell/part-3.md) |
|
|
866
|
+
| Clojure | [Part III: エラーハンドリング](../clojure/part-3.md) |
|
|
867
|
+
| Elixir | [Part III: エラーハンドリング](../elixir/part-3.md) |
|
|
868
|
+
| Rust | [Part III: エラーハンドリング](../rust/part-3.md) |
|
|
869
|
+
| Python | [Part III: エラーハンドリング](../python/part-3.md) |
|
|
870
|
+
| TypeScript | [Part III: エラーハンドリング](../typescript/part-3.md) |
|
|
871
|
+
| Ruby | [Part III: エラーハンドリング](../ruby/part-3.md) |
|