@k2works/claude-code-booster 2.7.1 → 3.1.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/lib/assets/docs/article/functional-desgin-ppp/all/01-immutability-and-data-transformation.md +475 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/02-function-composition.md +519 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/03-polymorphism.md +537 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/04-data-validation.md +300 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/05-property-based-testing.md +320 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/06-tdd-and-functional.md +498 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/07-composite-pattern.md +298 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/08-decorator-pattern.md +291 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/09-adapter-pattern.md +336 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/10-strategy-pattern.md +303 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/11-command-pattern.md +286 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/12-visitor-pattern.md +322 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/13-abstract-factory-pattern.md +319 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/14-abstract-server-pattern.md +365 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/15-gossiping-bus-drivers.md +156 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/16-payroll-system.md +178 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/17-video-rental-system.md +312 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/18-concurrency-system.md +287 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/19-wa-tor-simulation.md +286 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/20-pattern-interactions.md +274 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/21-best-practices.md +294 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/22-oo-to-fp-migration.md +337 -0
- package/lib/assets/docs/article/functional-desgin-ppp/all/index.md +388 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/01-immutability-and-data-transformation.md +271 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/02-function-composition.md +380 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/03-polymorphism.md +384 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/04-clojure-spec.md +350 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/05-property-based-testing.md +352 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/06-tdd-in-functional.md +383 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/07-composite-pattern.md +529 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/08-decorator-pattern.md +395 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/09-adapter-pattern.md +399 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/10-strategy-pattern.md +485 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/11-command-pattern.md +566 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/12-visitor-pattern.md +567 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/13-abstract-factory-pattern.md +475 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/14-abstract-server-pattern.md +462 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/15-gossiping-bus-drivers.md +323 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/16-payroll-system.md +401 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/17-video-rental-system.md +450 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/18-concurrency-system.md +475 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/19-wator-simulation.md +739 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/20-pattern-interactions.md +562 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/21-best-practices.md +506 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/22-oo-to-fp-migration.md +526 -0
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/index.md +197 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/01-immutability-and-data-transformation.md +381 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/02-function-composition.md +374 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/03-polymorphism.md +375 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/04-data-validation.md +195 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/05-property-based-testing.md +268 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/06-tdd-and-fp.md +294 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/07-effects-and-pure-functions.md +164 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/08-error-handling-strategies.md +168 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/09-io-and-external-systems.md +254 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/10-concurrency-patterns.md +269 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/11-command-pattern.md +148 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/12-visitor-pattern.md +176 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/13-abstract-factory-pattern.md +604 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/14-abstract-server-pattern.md +729 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/15-gossiping-bus-drivers.md +291 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/16-payroll-system.md +420 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/17-video-rental-system.md +319 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/18-concurrency-system.md +466 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/19-wator-simulation.md +523 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/20-pattern-interactions.md +287 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/21-best-practices.md +340 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/22-oo-to-fp-migration.md +395 -0
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/index.md +204 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/01-immutability-and-data-transformation.md +382 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/02-function-composition.md +452 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/03-polymorphism.md +495 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/04-data-validation.md +416 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/05-property-based-testing.md +382 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/06-tdd-functional.md +687 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/07-composite-pattern.md +442 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/08-decorator-pattern.md +479 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/09-adapter-pattern.md +479 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/10-strategy-pattern.md +427 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/11-command-pattern.md +428 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/12-visitor-pattern.md +339 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/13-abstract-factory-pattern.md +309 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/14-abstract-server-pattern.md +596 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/15-gossiping-bus-drivers.md +353 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/16-payroll-system.md +350 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/17-video-rental-system.md +412 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/18-concurrency-system.md +367 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/19-wator-simulation.md +401 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/20-pattern-interactions.md +291 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/21-best-practices.md +320 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/22-oo-to-fp-migration.md +322 -0
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/index.md +230 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/01-immutability-and-data-transformation.md +298 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/02-function-composition.md +304 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/03-polymorphism.md +362 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/04-data-validation.md +257 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/05-property-based-testing.md +254 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/06-tdd-functional.md +283 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/07-composite-pattern.md +395 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/08-decorator-pattern.md +319 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/09-adapter-pattern.md +382 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/10-strategy-pattern.md +287 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/11-command-pattern.md +303 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/12-visitor-pattern.md +326 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/13-abstract-factory-pattern.md +332 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/14-abstract-server-pattern.md +379 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/15-gossiping-bus-drivers.md +175 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/16-payroll-system.md +219 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/17-video-rental-system.md +244 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/18-concurrency-system.md +363 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/19-wator-simulation.md +438 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/20-pattern-interactions.md +323 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/21-best-practices.md +403 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/22-oo-to-fp-migration.md +469 -0
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/index.md +174 -0
- package/lib/assets/docs/article/functional-desgin-ppp/index.md +90 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/01-immutability-and-data-transformation.md +448 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/02-function-composition.md +463 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/03-polymorphism.md +425 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/04-data-validation.md +273 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/05-property-based-testing.md +247 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/06-tdd-and-functional.md +841 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/07-composite-pattern.md +384 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/08-decorator-pattern.md +383 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/09-adapter-pattern.md +339 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/10-strategy-pattern.md +331 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/11-command-pattern.md +356 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/12-visitor-pattern.md +379 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/13-abstract-factory-pattern.md +361 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/14-abstract-server-pattern.md +392 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/15-gossiping-bus-drivers.md +300 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/16-payroll-system.md +297 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/17-video-rental-system.md +304 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/18-concurrency-system.md +315 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/19-wator-simulation.md +311 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/20-pattern-interactions.md +304 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/21-best-practices.md +336 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/22-oo-to-fp-migration.md +349 -0
- package/lib/assets/docs/article/functional-desgin-ppp/rust/index.md +199 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/01-immutability-and-data-transformation.md +326 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/02-function-composition.md +348 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/03-polymorphism.md +357 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/04-data-validation.md +364 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/05-property-based-testing.md +515 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/06-tdd-functional.md +557 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/07-composite-pattern.md +363 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/08-decorator-pattern.md +327 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/09-adapter-pattern.md +517 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/10-strategy-pattern.md +441 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/11-command-pattern.md +407 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/12-visitor-pattern.md +379 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/13-abstract-factory-pattern.md +398 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/14-abstract-server-pattern.md +476 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/15-gossiping-bus-drivers.md +389 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/16-payroll-system.md +342 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/17-video-rental-system.md +324 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/18-concurrency-system.md +730 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/19-wator-simulation.md +624 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/20-pattern-interactions.md +512 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/21-best-practices.md +427 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/22-oo-to-fp-migration.md +682 -0
- package/lib/assets/docs/article/functional-desgin-ppp/scala/index.md +199 -0
- package/lib/assets/docs/article/getting-start-tdd/clojure/01-todo-list-and-first-test.md +166 -0
- package/lib/assets/docs/article/getting-start-tdd/clojure/02-fake-it-and-triangulation.md +162 -0
- package/lib/assets/docs/article/getting-start-tdd/clojure/03-obvious-implementation-and-refactoring.md +135 -0
- package/lib/assets/docs/article/getting-start-tdd/clojure/04-version-control-and-conventional-commits.md +88 -0
- package/lib/assets/docs/article/getting-start-tdd/clojure/05-package-management-and-static-analysis.md +299 -0
- package/lib/assets/docs/article/getting-start-tdd/clojure/06-task-runner-and-ci-cd.md +241 -0
- package/lib/assets/docs/article/getting-start-tdd/clojure/07-protocols-and-records.md +131 -0
- package/lib/assets/docs/article/getting-start-tdd/clojure/08-multimethods-and-design-patterns.md +130 -0
- package/lib/assets/docs/article/getting-start-tdd/clojure/09-namespaces-and-module-design.md +127 -0
- package/lib/assets/docs/article/getting-start-tdd/clojure/10-higher-order-functions-and-composition.md +114 -0
- package/lib/assets/docs/article/getting-start-tdd/clojure/11-persistent-data-and-pipeline.md +138 -0
- package/lib/assets/docs/article/getting-start-tdd/clojure/12-error-handling-and-spec.md +161 -0
- package/lib/assets/docs/article/getting-start-tdd/clojure/index.md +65 -0
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter01.md +232 -0
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter02.md +244 -0
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter03.md +202 -0
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter04.md +92 -0
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter05.md +256 -0
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter06.md +195 -0
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter07.md +214 -0
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter08.md +249 -0
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter09.md +174 -0
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter10.md +166 -0
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter11.md +192 -0
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter12.md +211 -0
- package/lib/assets/docs/article/getting-start-tdd/csharp/index.md +83 -0
- package/lib/assets/docs/article/getting-start-tdd/elixir/01-todo-list-and-first-test.md +87 -0
- package/lib/assets/docs/article/getting-start-tdd/elixir/02-fake-it-and-triangulation.md +95 -0
- package/lib/assets/docs/article/getting-start-tdd/elixir/03-obvious-implementation-and-refactoring.md +109 -0
- package/lib/assets/docs/article/getting-start-tdd/elixir/04-version-control-and-conventional-commits.md +96 -0
- package/lib/assets/docs/article/getting-start-tdd/elixir/05-package-management-and-static-analysis.md +88 -0
- package/lib/assets/docs/article/getting-start-tdd/elixir/06-task-runner-and-ci-cd.md +71 -0
- package/lib/assets/docs/article/getting-start-tdd/elixir/07-structs-and-protocols.md +110 -0
- package/lib/assets/docs/article/getting-start-tdd/elixir/08-pattern-matching-and-guards.md +108 -0
- package/lib/assets/docs/article/getting-start-tdd/elixir/09-module-design-and-behaviours.md +104 -0
- package/lib/assets/docs/article/getting-start-tdd/elixir/10-higher-order-functions-and-pipeline.md +178 -0
- package/lib/assets/docs/article/getting-start-tdd/elixir/11-stream-and-lazy-evaluation.md +142 -0
- package/lib/assets/docs/article/getting-start-tdd/elixir/12-error-handling-and-with.md +145 -0
- package/lib/assets/docs/article/getting-start-tdd/elixir/index.md +35 -0
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter01.md +202 -0
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter02.md +246 -0
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter03.md +218 -0
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter04.md +179 -0
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter05.md +267 -0
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter06.md +190 -0
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter07.md +161 -0
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter08.md +175 -0
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter09.md +222 -0
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter10.md +189 -0
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter11.md +212 -0
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter12.md +215 -0
- package/lib/assets/docs/article/getting-start-tdd/fsharp/index.md +71 -0
- package/lib/assets/docs/article/getting-start-tdd/go/01-todo-list-and-first-test.md +213 -0
- package/lib/assets/docs/article/getting-start-tdd/go/02-fake-it-and-triangulation.md +302 -0
- package/lib/assets/docs/article/getting-start-tdd/go/03-obvious-implementation-and-refactoring.md +339 -0
- package/lib/assets/docs/article/getting-start-tdd/go/04-version-control-and-conventional-commits.md +112 -0
- package/lib/assets/docs/article/getting-start-tdd/go/05-package-management-and-static-analysis.md +272 -0
- package/lib/assets/docs/article/getting-start-tdd/go/06-task-runner-and-ci-cd.md +233 -0
- package/lib/assets/docs/article/getting-start-tdd/go/07-encapsulation-and-polymorphism.md +394 -0
- package/lib/assets/docs/article/getting-start-tdd/go/08-design-patterns.md +422 -0
- package/lib/assets/docs/article/getting-start-tdd/go/09-solid-principles-and-module-design.md +400 -0
- package/lib/assets/docs/article/getting-start-tdd/go/10-higher-order-functions-and-composition.md +226 -0
- package/lib/assets/docs/article/getting-start-tdd/go/11-immutable-data-and-pipeline.md +296 -0
- package/lib/assets/docs/article/getting-start-tdd/go/12-error-handling-and-type-safety.md +411 -0
- package/lib/assets/docs/article/getting-start-tdd/go/index.md +83 -0
- package/lib/assets/docs/article/getting-start-tdd/haskell/01-todo-list-and-first-test.md +279 -0
- package/lib/assets/docs/article/getting-start-tdd/haskell/02-fake-it-and-triangulation.md +337 -0
- package/lib/assets/docs/article/getting-start-tdd/haskell/03-obvious-implementation-and-refactoring.md +257 -0
- package/lib/assets/docs/article/getting-start-tdd/haskell/04-version-control-and-conventional-commits.md +182 -0
- package/lib/assets/docs/article/getting-start-tdd/haskell/05-package-management-and-static-analysis.md +313 -0
- package/lib/assets/docs/article/getting-start-tdd/haskell/06-task-runner-and-ci-cd.md +309 -0
- package/lib/assets/docs/article/getting-start-tdd/haskell/07-algebraic-data-types-and-type-classes.md +412 -0
- package/lib/assets/docs/article/getting-start-tdd/haskell/08-pattern-matching-and-guards.md +390 -0
- package/lib/assets/docs/article/getting-start-tdd/haskell/09-module-design-and-smart-constructors.md +461 -0
- package/lib/assets/docs/article/getting-start-tdd/haskell/10-higher-order-functions-and-currying.md +434 -0
- package/lib/assets/docs/article/getting-start-tdd/haskell/11-function-composition-and-point-free.md +392 -0
- package/lib/assets/docs/article/getting-start-tdd/haskell/12-monad-and-error-handling.md +631 -0
- package/lib/assets/docs/article/getting-start-tdd/haskell/index.md +49 -0
- package/lib/assets/docs/article/getting-start-tdd/index.md +93 -0
- package/lib/assets/docs/article/getting-start-tdd/integration/01-language-overview.md +375 -0
- package/lib/assets/docs/article/getting-start-tdd/integration/02-test-framework-comparison.md +349 -0
- package/lib/assets/docs/article/getting-start-tdd/integration/03-tdd-pattern-comparison.md +445 -0
- package/lib/assets/docs/article/getting-start-tdd/integration/04-type-system-comparison.md +405 -0
- package/lib/assets/docs/article/getting-start-tdd/integration/05-dev-environment-comparison.md +330 -0
- package/lib/assets/docs/article/getting-start-tdd/integration/06-learning-roadmap.md +274 -0
- package/lib/assets/docs/article/getting-start-tdd/integration/index.md +69 -0
- package/lib/assets/docs/article/getting-start-tdd/java/01-todo-list-and-first-test.md +234 -0
- package/lib/assets/docs/article/getting-start-tdd/java/02-fake-it-and-triangulation.md +261 -0
- package/lib/assets/docs/article/getting-start-tdd/java/03-obvious-implementation-and-refactoring.md +185 -0
- package/lib/assets/docs/article/getting-start-tdd/java/04-version-control-and-conventional-commits.md +115 -0
- package/lib/assets/docs/article/getting-start-tdd/java/05-package-management-and-static-analysis.md +382 -0
- package/lib/assets/docs/article/getting-start-tdd/java/06-task-runner-and-ci-cd.md +272 -0
- package/lib/assets/docs/article/getting-start-tdd/java/07-encapsulation-and-polymorphism.md +626 -0
- package/lib/assets/docs/article/getting-start-tdd/java/08-design-patterns.md +393 -0
- package/lib/assets/docs/article/getting-start-tdd/java/09-solid-principles-and-module-design.md +310 -0
- package/lib/assets/docs/article/getting-start-tdd/java/10-higher-order-functions-and-composition.md +188 -0
- package/lib/assets/docs/article/getting-start-tdd/java/11-immutable-data-and-pipeline.md +167 -0
- package/lib/assets/docs/article/getting-start-tdd/java/12-error-handling-and-type-safety.md +205 -0
- package/lib/assets/docs/article/getting-start-tdd/java/index.md +61 -0
- package/lib/assets/docs/article/getting-start-tdd/node/01-todo-list-and-first-test.md +244 -0
- package/lib/assets/docs/article/getting-start-tdd/node/02-fake-it-and-triangulation.md +262 -0
- package/lib/assets/docs/article/getting-start-tdd/node/03-obvious-implementation-and-refactoring.md +169 -0
- package/lib/assets/docs/article/getting-start-tdd/node/04-version-control-and-conventional-commits.md +112 -0
- package/lib/assets/docs/article/getting-start-tdd/node/05-package-management-and-static-analysis.md +314 -0
- package/lib/assets/docs/article/getting-start-tdd/node/06-task-runner-and-ci-cd.md +235 -0
- package/lib/assets/docs/article/getting-start-tdd/node/07-encapsulation-and-polymorphism.md +327 -0
- package/lib/assets/docs/article/getting-start-tdd/node/08-design-patterns.md +322 -0
- package/lib/assets/docs/article/getting-start-tdd/node/09-solid-principles-and-module-design.md +285 -0
- package/lib/assets/docs/article/getting-start-tdd/node/10-higher-order-functions-and-composition.md +199 -0
- package/lib/assets/docs/article/getting-start-tdd/node/11-immutable-data-and-pipeline.md +207 -0
- package/lib/assets/docs/article/getting-start-tdd/node/12-error-handling-and-type-safety.md +295 -0
- package/lib/assets/docs/article/getting-start-tdd/node/index.md +56 -0
- package/lib/assets/docs/article/getting-start-tdd/php/01-todo-list-and-first-test.md +259 -0
- package/lib/assets/docs/article/getting-start-tdd/php/02-fake-it-and-triangulation.md +200 -0
- package/lib/assets/docs/article/getting-start-tdd/php/03-obvious-implementation-and-refactoring.md +248 -0
- package/lib/assets/docs/article/getting-start-tdd/php/04-version-control-and-conventional-commits.md +141 -0
- package/lib/assets/docs/article/getting-start-tdd/php/05-package-management-and-static-analysis.md +410 -0
- package/lib/assets/docs/article/getting-start-tdd/php/06-task-runner-and-ci-cd.md +321 -0
- package/lib/assets/docs/article/getting-start-tdd/php/07-encapsulation-and-polymorphism.md +372 -0
- package/lib/assets/docs/article/getting-start-tdd/php/08-design-patterns.md +453 -0
- package/lib/assets/docs/article/getting-start-tdd/php/09-solid-principles-and-module-design.md +460 -0
- package/lib/assets/docs/article/getting-start-tdd/php/10-higher-order-functions-and-composition.md +182 -0
- package/lib/assets/docs/article/getting-start-tdd/php/11-immutable-data-and-pipeline.md +266 -0
- package/lib/assets/docs/article/getting-start-tdd/php/12-error-handling-and-type-safety.md +308 -0
- package/lib/assets/docs/article/getting-start-tdd/php/index.md +84 -0
- package/lib/assets/docs/article/getting-start-tdd/python/01-todo-list-and-first-test.md +201 -0
- package/lib/assets/docs/article/getting-start-tdd/python/02-fake-it-and-triangulation.md +247 -0
- package/lib/assets/docs/article/getting-start-tdd/python/03-obvious-implementation-and-refactoring.md +199 -0
- package/lib/assets/docs/article/getting-start-tdd/python/04-version-control-and-conventional-commits.md +87 -0
- package/lib/assets/docs/article/getting-start-tdd/python/05-package-management-and-static-analysis.md +274 -0
- package/lib/assets/docs/article/getting-start-tdd/python/06-task-runner-and-ci-cd.md +190 -0
- package/lib/assets/docs/article/getting-start-tdd/python/07-encapsulation-and-polymorphism.md +208 -0
- package/lib/assets/docs/article/getting-start-tdd/python/08-design-patterns.md +172 -0
- package/lib/assets/docs/article/getting-start-tdd/python/09-solid-principles-and-module-design.md +130 -0
- package/lib/assets/docs/article/getting-start-tdd/python/10-higher-order-functions-and-composition.md +122 -0
- package/lib/assets/docs/article/getting-start-tdd/python/11-immutable-data-and-pipeline.md +116 -0
- package/lib/assets/docs/article/getting-start-tdd/python/12-error-handling-and-type-safety.md +126 -0
- package/lib/assets/docs/article/getting-start-tdd/python/index.md +55 -0
- package/lib/assets/docs/article/getting-start-tdd/ruby/01-todo-list-and-first-test.md +231 -0
- package/lib/assets/docs/article/getting-start-tdd/ruby/02-fake-it-and-triangulation.md +238 -0
- package/lib/assets/docs/article/getting-start-tdd/ruby/03-obvious-implementation-and-refactoring.md +228 -0
- package/lib/assets/docs/article/getting-start-tdd/ruby/04-version-control-and-conventional-commits.md +112 -0
- package/lib/assets/docs/article/getting-start-tdd/ruby/05-package-management-and-static-analysis.md +287 -0
- package/lib/assets/docs/article/getting-start-tdd/ruby/06-task-runner-and-ci-cd.md +248 -0
- package/lib/assets/docs/article/getting-start-tdd/ruby/07-encapsulation-and-polymorphism.md +279 -0
- package/lib/assets/docs/article/getting-start-tdd/ruby/08-design-patterns.md +329 -0
- package/lib/assets/docs/article/getting-start-tdd/ruby/09-solid-principles-and-module-design.md +196 -0
- package/lib/assets/docs/article/getting-start-tdd/ruby/10-higher-order-functions-and-composition.md +175 -0
- package/lib/assets/docs/article/getting-start-tdd/ruby/11-immutable-data-and-pipeline.md +233 -0
- package/lib/assets/docs/article/getting-start-tdd/ruby/12-error-handling-and-type-safety.md +398 -0
- package/lib/assets/docs/article/getting-start-tdd/ruby/index.md +83 -0
- package/lib/assets/docs/article/getting-start-tdd/rust/01-todo-list-and-first-test.md +211 -0
- package/lib/assets/docs/article/getting-start-tdd/rust/02-fake-it-and-triangulation.md +264 -0
- package/lib/assets/docs/article/getting-start-tdd/rust/03-obvious-implementation-and-refactoring.md +233 -0
- package/lib/assets/docs/article/getting-start-tdd/rust/04-version-control-and-conventional-commits.md +92 -0
- package/lib/assets/docs/article/getting-start-tdd/rust/05-package-management-and-static-analysis.md +212 -0
- package/lib/assets/docs/article/getting-start-tdd/rust/06-task-runner-and-ci-cd.md +164 -0
- package/lib/assets/docs/article/getting-start-tdd/rust/07-encapsulation-and-polymorphism.md +142 -0
- package/lib/assets/docs/article/getting-start-tdd/rust/08-design-patterns.md +145 -0
- package/lib/assets/docs/article/getting-start-tdd/rust/09-solid-principles-and-module-design.md +110 -0
- package/lib/assets/docs/article/getting-start-tdd/rust/10-higher-order-functions-and-composition.md +94 -0
- package/lib/assets/docs/article/getting-start-tdd/rust/11-immutable-data-and-pipeline.md +105 -0
- package/lib/assets/docs/article/getting-start-tdd/rust/12-error-handling-and-type-safety.md +112 -0
- package/lib/assets/docs/article/getting-start-tdd/rust/index.md +83 -0
- package/lib/assets/docs/article/getting-start-tdd/scala/01-todo-list-and-first-test.md +111 -0
- package/lib/assets/docs/article/getting-start-tdd/scala/02-fake-it-and-triangulation.md +107 -0
- package/lib/assets/docs/article/getting-start-tdd/scala/03-obvious-implementation-and-refactoring.md +99 -0
- package/lib/assets/docs/article/getting-start-tdd/scala/04-version-control-and-conventional-commits.md +123 -0
- package/lib/assets/docs/article/getting-start-tdd/scala/05-package-management-and-static-analysis.md +196 -0
- package/lib/assets/docs/article/getting-start-tdd/scala/06-task-runner-and-ci-cd.md +186 -0
- package/lib/assets/docs/article/getting-start-tdd/scala/07-case-classes-and-traits.md +139 -0
- package/lib/assets/docs/article/getting-start-tdd/scala/08-pattern-matching-and-sealed-traits.md +106 -0
- package/lib/assets/docs/article/getting-start-tdd/scala/09-packages-and-module-design.md +75 -0
- package/lib/assets/docs/article/getting-start-tdd/scala/10-higher-order-functions-and-composition.md +104 -0
- package/lib/assets/docs/article/getting-start-tdd/scala/11-collections-and-lazy-evaluation.md +94 -0
- package/lib/assets/docs/article/getting-start-tdd/scala/12-error-handling-and-type-safety.md +92 -0
- package/lib/assets/docs/article/getting-start-tdd/scala/index.md +65 -0
- package/lib/assets/docs/article/grokking-concurrency/all/index.md +404 -0
- package/lib/assets/docs/article/grokking-concurrency/all/part-1-ch02-sequential.md +554 -0
- package/lib/assets/docs/article/grokking-concurrency/all/part-2-ch04-05-threads.md +469 -0
- package/lib/assets/docs/article/grokking-concurrency/all/part-3-ch06-multitasking.md +520 -0
- package/lib/assets/docs/article/grokking-concurrency/all/part-4-ch07-parallel-patterns.md +420 -0
- package/lib/assets/docs/article/grokking-concurrency/all/part-5-ch08-09-synchronization.md +510 -0
- package/lib/assets/docs/article/grokking-concurrency/all/part-6-ch10-11-nonblocking-io.md +435 -0
- package/lib/assets/docs/article/grokking-concurrency/all/part-7-ch12-async.md +465 -0
- package/lib/assets/docs/article/grokking-concurrency/all/part-8-ch13-mapreduce.md +377 -0
- package/lib/assets/docs/article/grokking-concurrency/clojure/index.md +116 -0
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-1.md +108 -0
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-2.md +101 -0
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-3.md +122 -0
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-4.md +123 -0
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-5.md +118 -0
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-6.md +89 -0
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-7.md +100 -0
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-8.md +120 -0
- package/lib/assets/docs/article/grokking-concurrency/csharp/index.md +101 -0
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-1.md +97 -0
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-2.md +123 -0
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-3.md +101 -0
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-4.md +112 -0
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-5.md +99 -0
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-6.md +61 -0
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-7.md +84 -0
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-8.md +92 -0
- package/lib/assets/docs/article/grokking-concurrency/fsharp/index.md +65 -0
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-1.md +80 -0
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-2.md +103 -0
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-3.md +94 -0
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-4.md +110 -0
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-5.md +104 -0
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-6.md +93 -0
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-7.md +121 -0
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-8.md +107 -0
- package/lib/assets/docs/article/grokking-concurrency/haskell/index.md +248 -0
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-1.md +96 -0
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-2.md +96 -0
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-3.md +91 -0
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-4.md +106 -0
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-5.md +99 -0
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-6.md +95 -0
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-7.md +111 -0
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-8.md +118 -0
- package/lib/assets/docs/article/grokking-concurrency/index.md +66 -0
- package/lib/assets/docs/article/grokking-concurrency/java/index.md +102 -0
- package/lib/assets/docs/article/grokking-concurrency/java/part-1.md +308 -0
- package/lib/assets/docs/article/grokking-concurrency/java/part-2.md +334 -0
- package/lib/assets/docs/article/grokking-concurrency/java/part-3.md +221 -0
- package/lib/assets/docs/article/grokking-concurrency/java/part-4.md +213 -0
- package/lib/assets/docs/article/grokking-concurrency/java/part-5.md +112 -0
- package/lib/assets/docs/article/grokking-concurrency/java/part-6.md +69 -0
- package/lib/assets/docs/article/grokking-concurrency/java/part-7.md +101 -0
- package/lib/assets/docs/article/grokking-concurrency/java/part-8.md +101 -0
- package/lib/assets/docs/article/grokking-concurrency/python/index.md +313 -0
- package/lib/assets/docs/article/grokking-concurrency/python/part-1.md +239 -0
- package/lib/assets/docs/article/grokking-concurrency/python/part-2.md +418 -0
- package/lib/assets/docs/article/grokking-concurrency/python/part-3.md +227 -0
- package/lib/assets/docs/article/grokking-concurrency/python/part-4.md +299 -0
- package/lib/assets/docs/article/grokking-concurrency/python/part-5.md +315 -0
- package/lib/assets/docs/article/grokking-concurrency/python/part-6.md +297 -0
- package/lib/assets/docs/article/grokking-concurrency/python/part-7.md +314 -0
- package/lib/assets/docs/article/grokking-concurrency/python/part-8.md +360 -0
- package/lib/assets/docs/article/grokking-concurrency/rust/index.md +270 -0
- package/lib/assets/docs/article/grokking-concurrency/rust/part-1.md +108 -0
- package/lib/assets/docs/article/grokking-concurrency/rust/part-2.md +120 -0
- package/lib/assets/docs/article/grokking-concurrency/rust/part-3.md +126 -0
- package/lib/assets/docs/article/grokking-concurrency/rust/part-4.md +175 -0
- package/lib/assets/docs/article/grokking-concurrency/rust/part-5.md +158 -0
- package/lib/assets/docs/article/grokking-concurrency/rust/part-6.md +94 -0
- package/lib/assets/docs/article/grokking-concurrency/rust/part-7.md +133 -0
- package/lib/assets/docs/article/grokking-concurrency/rust/part-8.md +155 -0
- package/lib/assets/docs/article/grokking-concurrency/scala/index.md +69 -0
- package/lib/assets/docs/article/grokking-concurrency/scala/part-1.md +78 -0
- package/lib/assets/docs/article/grokking-concurrency/scala/part-2.md +112 -0
- package/lib/assets/docs/article/grokking-concurrency/scala/part-3.md +93 -0
- package/lib/assets/docs/article/grokking-concurrency/scala/part-4.md +110 -0
- package/lib/assets/docs/article/grokking-concurrency/scala/part-5.md +119 -0
- package/lib/assets/docs/article/grokking-concurrency/scala/part-6.md +83 -0
- package/lib/assets/docs/article/grokking-concurrency/scala/part-7.md +131 -0
- package/lib/assets/docs/article/grokking-concurrency/scala/part-8.md +129 -0
- package/lib/assets/docs/article/grokkingfp/all/index.md +368 -0
- package/lib/assets/docs/article/grokkingfp/all/part-1-ch01-fp-introduction.md +530 -0
- package/lib/assets/docs/article/grokkingfp/all/part-1-ch02-pure-functions.md +923 -0
- package/lib/assets/docs/article/grokkingfp/all/part-2-ch03-immutable-data.md +1122 -0
- package/lib/assets/docs/article/grokkingfp/all/part-2-ch04-higher-order-functions.md +1104 -0
- package/lib/assets/docs/article/grokkingfp/all/part-2-ch05-flatmap.md +1026 -0
- package/lib/assets/docs/article/grokkingfp/all/part-3-ch06-option.md +777 -0
- package/lib/assets/docs/article/grokkingfp/all/part-3-ch07-either-adt.md +871 -0
- package/lib/assets/docs/article/grokkingfp/all/part-4-ch08-io-monad.md +972 -0
- package/lib/assets/docs/article/grokkingfp/all/part-4-ch09-streams.md +926 -0
- package/lib/assets/docs/article/grokkingfp/all/part-5-ch10-concurrency.md +870 -0
- package/lib/assets/docs/article/grokkingfp/all/part-6-ch11-application.md +715 -0
- package/lib/assets/docs/article/grokkingfp/all/part-6-ch12-testing.md +626 -0
- package/lib/assets/docs/article/grokkingfp/all/writing-plan.md +696 -0
- package/lib/assets/docs/article/grokkingfp/clojure/index.md +276 -0
- package/lib/assets/docs/article/grokkingfp/clojure/part-1.md +667 -0
- package/lib/assets/docs/article/grokkingfp/clojure/part-2.md +643 -0
- package/lib/assets/docs/article/grokkingfp/clojure/part-3.md +620 -0
- package/lib/assets/docs/article/grokkingfp/clojure/part-4.md +697 -0
- package/lib/assets/docs/article/grokkingfp/clojure/part-5.md +751 -0
- package/lib/assets/docs/article/grokkingfp/clojure/part-6.md +721 -0
- package/lib/assets/docs/article/grokkingfp/csharp/index.md +246 -0
- package/lib/assets/docs/article/grokkingfp/csharp/part-1.md +811 -0
- package/lib/assets/docs/article/grokkingfp/csharp/part-2.md +971 -0
- package/lib/assets/docs/article/grokkingfp/csharp/part-3.md +981 -0
- package/lib/assets/docs/article/grokkingfp/csharp/part-4.md +949 -0
- package/lib/assets/docs/article/grokkingfp/csharp/part-5.md +947 -0
- package/lib/assets/docs/article/grokkingfp/csharp/part-6.md +739 -0
- package/lib/assets/docs/article/grokkingfp/elixir/index.md +203 -0
- package/lib/assets/docs/article/grokkingfp/elixir/part-1.md +710 -0
- package/lib/assets/docs/article/grokkingfp/elixir/part-2.md +838 -0
- package/lib/assets/docs/article/grokkingfp/elixir/part-3.md +985 -0
- package/lib/assets/docs/article/grokkingfp/elixir/part-4.md +974 -0
- package/lib/assets/docs/article/grokkingfp/elixir/part-5.md +1284 -0
- package/lib/assets/docs/article/grokkingfp/elixir/part-6.md +1047 -0
- package/lib/assets/docs/article/grokkingfp/fsharp/index.md +210 -0
- package/lib/assets/docs/article/grokkingfp/fsharp/part-1.md +714 -0
- package/lib/assets/docs/article/grokkingfp/fsharp/part-2.md +961 -0
- package/lib/assets/docs/article/grokkingfp/fsharp/part-3.md +972 -0
- package/lib/assets/docs/article/grokkingfp/fsharp/part-4.md +832 -0
- package/lib/assets/docs/article/grokkingfp/fsharp/part-5.md +911 -0
- package/lib/assets/docs/article/grokkingfp/fsharp/part-6.md +920 -0
- package/lib/assets/docs/article/grokkingfp/haskell/index.md +234 -0
- package/lib/assets/docs/article/grokkingfp/haskell/part-1.md +591 -0
- package/lib/assets/docs/article/grokkingfp/haskell/part-2.md +866 -0
- package/lib/assets/docs/article/grokkingfp/haskell/part-3.md +915 -0
- package/lib/assets/docs/article/grokkingfp/haskell/part-4.md +876 -0
- package/lib/assets/docs/article/grokkingfp/haskell/part-5.md +845 -0
- package/lib/assets/docs/article/grokkingfp/haskell/part-6.md +842 -0
- package/lib/assets/docs/article/grokkingfp/index.md +143 -0
- package/lib/assets/docs/article/grokkingfp/java/index.md +211 -0
- package/lib/assets/docs/article/grokkingfp/java/part-1.md +646 -0
- package/lib/assets/docs/article/grokkingfp/java/part-2.md +667 -0
- package/lib/assets/docs/article/grokkingfp/java/part-3.md +672 -0
- package/lib/assets/docs/article/grokkingfp/java/part-4.md +771 -0
- package/lib/assets/docs/article/grokkingfp/java/part-5.md +959 -0
- package/lib/assets/docs/article/grokkingfp/java/part-6.md +1324 -0
- package/lib/assets/docs/article/grokkingfp/python/index.md +258 -0
- package/lib/assets/docs/article/grokkingfp/python/part-1.md +437 -0
- package/lib/assets/docs/article/grokkingfp/python/part-2.md +958 -0
- package/lib/assets/docs/article/grokkingfp/python/part-3.md +1004 -0
- package/lib/assets/docs/article/grokkingfp/python/part-4.md +765 -0
- package/lib/assets/docs/article/grokkingfp/python/part-5.md +747 -0
- package/lib/assets/docs/article/grokkingfp/python/part-6.md +861 -0
- package/lib/assets/docs/article/grokkingfp/ruby/index.md +330 -0
- package/lib/assets/docs/article/grokkingfp/ruby/part-1.md +753 -0
- package/lib/assets/docs/article/grokkingfp/ruby/part-2.md +938 -0
- package/lib/assets/docs/article/grokkingfp/ruby/part-3.md +946 -0
- package/lib/assets/docs/article/grokkingfp/ruby/part-4.md +921 -0
- package/lib/assets/docs/article/grokkingfp/ruby/part-5.md +908 -0
- package/lib/assets/docs/article/grokkingfp/ruby/part-6.md +1410 -0
- package/lib/assets/docs/article/grokkingfp/rust/index.md +242 -0
- package/lib/assets/docs/article/grokkingfp/rust/part-1.md +634 -0
- package/lib/assets/docs/article/grokkingfp/rust/part-2.md +1060 -0
- package/lib/assets/docs/article/grokkingfp/rust/part-3.md +994 -0
- package/lib/assets/docs/article/grokkingfp/rust/part-4.md +571 -0
- package/lib/assets/docs/article/grokkingfp/rust/part-5.md +705 -0
- package/lib/assets/docs/article/grokkingfp/rust/part-6.md +508 -0
- package/lib/assets/docs/article/grokkingfp/scala/index.md +171 -0
- package/lib/assets/docs/article/grokkingfp/scala/part-1.md +541 -0
- package/lib/assets/docs/article/grokkingfp/scala/part-2.md +946 -0
- package/lib/assets/docs/article/grokkingfp/scala/part-3.md +917 -0
- package/lib/assets/docs/article/grokkingfp/scala/part-4.md +742 -0
- package/lib/assets/docs/article/grokkingfp/scala/part-5.md +722 -0
- package/lib/assets/docs/article/grokkingfp/scala/part-6.md +865 -0
- package/lib/assets/docs/article/grokkingfp/typescript/index.md +273 -0
- package/lib/assets/docs/article/grokkingfp/typescript/part-1.md +559 -0
- package/lib/assets/docs/article/grokkingfp/typescript/part-2.md +1129 -0
- package/lib/assets/docs/article/grokkingfp/typescript/part-3.md +842 -0
- package/lib/assets/docs/article/grokkingfp/typescript/part-4.md +1085 -0
- package/lib/assets/docs/article/grokkingfp/typescript/part-5.md +717 -0
- package/lib/assets/docs/article/grokkingfp/typescript/part-6.md +980 -0
- package/lib/assets/docs/article/index.md +36 -0
- package/lib/assets/docs/design/index.md +39 -27
- package/lib/assets/docs/development/index.md +11 -1
- package/lib/assets/docs/index.md +33 -103
- package/lib/assets/docs/operation/index.md +16 -6
- package/lib/assets/docs/reference/index.md +5 -4
- package/lib/assets/docs/requirements/index.md +13 -6
- package/lib/assets/docs/review/index.md +5 -0
- package/lib/assets/docs/strategy/index.md +15 -0
- package/lib/assets/docs/template/index.md +9 -5
- package/lib/assets/mkdocs.yml +33 -19
- package/package.json +1 -1
- package/lib/assets/docs/analysis/index.md +0 -8
- /package/lib/assets/docs/{analysis → strategy}/slide/.gitkeep +0 -0
|
@@ -0,0 +1,915 @@
|
|
|
1
|
+
# Part III: エラーハンドリングと Maybe/Either
|
|
2
|
+
|
|
3
|
+
本章では、関数型プログラミングにおける安全なエラーハンドリングを Haskell で学びます。`null` や例外に頼らず、`Maybe` と `Either` を使って型安全にエラーを扱う方法を習得します。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 第6章: Maybe 型による安全なエラーハンドリング
|
|
8
|
+
|
|
9
|
+
### 6.1 なぜ Maybe が必要か
|
|
10
|
+
|
|
11
|
+
従来のエラーハンドリングには問題があります。
|
|
12
|
+
|
|
13
|
+
```plantuml
|
|
14
|
+
@startuml
|
|
15
|
+
!theme plain
|
|
16
|
+
|
|
17
|
+
rectangle "従来のエラーハンドリング" {
|
|
18
|
+
rectangle "null を返す" as null_ret {
|
|
19
|
+
card "NullPointerException の危険"
|
|
20
|
+
card "コンパイル時に検出できない"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
rectangle "例外をスローする" as exception {
|
|
24
|
+
card "制御フローが複雑化"
|
|
25
|
+
card "純粋関数ではなくなる"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
rectangle "Maybe による解決" as maybe {
|
|
30
|
+
card "型で「値がないかもしれない」を表現"
|
|
31
|
+
card "コンパイル時にチェック"
|
|
32
|
+
card "純粋関数のまま"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
null_ret --> maybe : 置き換え
|
|
36
|
+
exception --> maybe : 置き換え
|
|
37
|
+
|
|
38
|
+
@enduml
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Haskell には null が存在しません。** 値が「ない」可能性は `Maybe` 型で明示的に表現します。
|
|
42
|
+
|
|
43
|
+
### 6.2 Maybe の基本
|
|
44
|
+
|
|
45
|
+
`Maybe a` は「`a` 型の値があるか、ないか」を表す型です。
|
|
46
|
+
|
|
47
|
+
```plantuml
|
|
48
|
+
@startuml
|
|
49
|
+
!theme plain
|
|
50
|
+
|
|
51
|
+
rectangle "Maybe a" as maybe {
|
|
52
|
+
rectangle "Just value" as just {
|
|
53
|
+
card "値が存在する"
|
|
54
|
+
card "value :: a を保持"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
rectangle "Nothing" as nothing {
|
|
58
|
+
card "値が存在しない"
|
|
59
|
+
card "null の代わり"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@enduml
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```haskell
|
|
67
|
+
data Maybe a = Nothing | Just a
|
|
68
|
+
|
|
69
|
+
-- 使用例
|
|
70
|
+
Just 5 :: Maybe Int -- 値がある
|
|
71
|
+
Nothing :: Maybe Int -- 値がない
|
|
72
|
+
Just "Hi" :: Maybe String -- 文字列がある
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**ソースファイル**: `app/haskell/src/Ch06/MaybeHandling.hs`
|
|
76
|
+
|
|
77
|
+
### 6.3 TV番組のパース例
|
|
78
|
+
|
|
79
|
+
TV番組の文字列をパースする例で Maybe の使い方を学びます。
|
|
80
|
+
|
|
81
|
+
```haskell
|
|
82
|
+
data TvShow = TvShow
|
|
83
|
+
{ tvTitle :: String
|
|
84
|
+
, tvStartYear :: Int
|
|
85
|
+
, tvEndYear :: Int
|
|
86
|
+
} deriving (Show, Eq)
|
|
87
|
+
|
|
88
|
+
-- 入力例: "Breaking Bad (2008-2013)"
|
|
89
|
+
-- 期待する出力: TvShow "Breaking Bad" 2008 2013
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### 安全でない実装(パターンマッチの失敗)
|
|
93
|
+
|
|
94
|
+
```haskell
|
|
95
|
+
parseShow :: String -> TvShow
|
|
96
|
+
parseShow rawShow =
|
|
97
|
+
let Just name = extractName rawShow -- 危険!
|
|
98
|
+
Just yearStart = extractYearStart rawShow -- 危険!
|
|
99
|
+
Just yearEnd = extractYearEnd rawShow -- 危険!
|
|
100
|
+
in TvShow name yearStart yearEnd
|
|
101
|
+
|
|
102
|
+
-- 正常ケース
|
|
103
|
+
parseShow "Breaking Bad (2008-2013)" -- TvShow "Breaking Bad" 2008 2013
|
|
104
|
+
|
|
105
|
+
-- 異常ケース → パターンマッチ失敗で例外!
|
|
106
|
+
parseShow "Invalid" -- *** Exception: ...
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### Maybe を使った安全な実装
|
|
110
|
+
|
|
111
|
+
```haskell
|
|
112
|
+
parseShowSafe :: String -> Maybe TvShow
|
|
113
|
+
parseShowSafe rawShow = do
|
|
114
|
+
name <- extractName rawShow
|
|
115
|
+
yearStart <- extractYearStart rawShow `orElse` extractSingleYear rawShow
|
|
116
|
+
yearEnd <- extractYearEnd rawShow `orElse` extractSingleYear rawShow
|
|
117
|
+
return $ TvShow name yearStart yearEnd
|
|
118
|
+
|
|
119
|
+
-- 正常ケース
|
|
120
|
+
parseShowSafe "Breaking Bad (2008-2013)"
|
|
121
|
+
-- Just (TvShow "Breaking Bad" 2008 2013)
|
|
122
|
+
|
|
123
|
+
-- 異常ケース → Nothing が返される(例外なし)
|
|
124
|
+
parseShowSafe "Invalid"
|
|
125
|
+
-- Nothing
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 6.4 小さな関数から組み立てる
|
|
129
|
+
|
|
130
|
+
複雑なパース処理を小さな関数に分解します。
|
|
131
|
+
|
|
132
|
+
```haskell
|
|
133
|
+
-- 名前を抽出
|
|
134
|
+
extractName :: String -> Maybe String
|
|
135
|
+
extractName rawShow =
|
|
136
|
+
let bracketOpen = elemIndex '(' rawShow
|
|
137
|
+
in case bracketOpen of
|
|
138
|
+
Just idx | idx > 0 -> Just $ trim $ take idx rawShow
|
|
139
|
+
_ -> Nothing
|
|
140
|
+
|
|
141
|
+
-- 開始年を抽出
|
|
142
|
+
extractYearStart :: String -> Maybe Int
|
|
143
|
+
extractYearStart rawShow = do
|
|
144
|
+
bracketOpen <- elemIndex '(' rawShow
|
|
145
|
+
dash <- elemIndex '-' rawShow
|
|
146
|
+
if dash > bracketOpen + 1
|
|
147
|
+
then readMaybe $ take (dash - bracketOpen - 1) $ drop (bracketOpen + 1) rawShow
|
|
148
|
+
else Nothing
|
|
149
|
+
|
|
150
|
+
-- 終了年を抽出
|
|
151
|
+
extractYearEnd :: String -> Maybe Int
|
|
152
|
+
extractYearEnd rawShow = do
|
|
153
|
+
dash <- elemIndex '-' rawShow
|
|
154
|
+
bracketClose <- elemIndex ')' rawShow
|
|
155
|
+
if bracketClose > dash + 1
|
|
156
|
+
then readMaybe $ take (bracketClose - dash - 1) $ drop (dash + 1) rawShow
|
|
157
|
+
else Nothing
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
```plantuml
|
|
161
|
+
@startuml
|
|
162
|
+
!theme plain
|
|
163
|
+
|
|
164
|
+
rectangle "パース処理の分解" {
|
|
165
|
+
card "\"Breaking Bad (2008-2013)\"" as input
|
|
166
|
+
|
|
167
|
+
rectangle "小さな関数" as funcs {
|
|
168
|
+
card "extractName" as name
|
|
169
|
+
card "extractYearStart" as start
|
|
170
|
+
card "extractYearEnd" as end
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
card "TvShow" as output
|
|
174
|
+
|
|
175
|
+
input --> funcs
|
|
176
|
+
funcs --> output : do 記法で合成
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@enduml
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 6.5 orElse によるフォールバック
|
|
183
|
+
|
|
184
|
+
`orElse` を使って、最初の Maybe が `Nothing` の場合に代替を試すことができます。
|
|
185
|
+
|
|
186
|
+
```haskell
|
|
187
|
+
-- orElse の実装
|
|
188
|
+
orElse :: Maybe a -> Maybe a -> Maybe a
|
|
189
|
+
orElse (Just x) _ = Just x
|
|
190
|
+
orElse Nothing y = y
|
|
191
|
+
|
|
192
|
+
-- 使用例
|
|
193
|
+
Just 7 `orElse` Just 8 -- Just 7 (最初が Just なのでそのまま)
|
|
194
|
+
Nothing `orElse` Just 8 -- Just 8 (最初が Nothing なので代替を使用)
|
|
195
|
+
Just 7 `orElse` Nothing -- Just 7
|
|
196
|
+
Nothing `orElse` Nothing -- Nothing
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
#### 単年の番組に対応する
|
|
200
|
+
|
|
201
|
+
「Chernobyl (2019)」のような単年の番組をパースできるようにします。
|
|
202
|
+
|
|
203
|
+
```haskell
|
|
204
|
+
extractSingleYear :: String -> Maybe Int
|
|
205
|
+
extractSingleYear rawShow =
|
|
206
|
+
case (elemIndex '-' rawShow, elemIndex '(' rawShow, elemIndex ')' rawShow) of
|
|
207
|
+
(Nothing, Just bo, Just bc) | bc > bo + 1 ->
|
|
208
|
+
readMaybe $ take (bc - bo - 1) $ drop (bo + 1) rawShow
|
|
209
|
+
_ -> Nothing
|
|
210
|
+
|
|
211
|
+
parseShowSafe :: String -> Maybe TvShow
|
|
212
|
+
parseShowSafe rawShow = do
|
|
213
|
+
name <- extractName rawShow
|
|
214
|
+
yearStart <- extractYearStart rawShow `orElse` extractSingleYear rawShow
|
|
215
|
+
yearEnd <- extractYearEnd rawShow `orElse` extractSingleYear rawShow
|
|
216
|
+
return $ TvShow name yearStart yearEnd
|
|
217
|
+
|
|
218
|
+
-- これで単年の番組もパースできる
|
|
219
|
+
parseShowSafe "Chernobyl (2019)"
|
|
220
|
+
-- Just (TvShow "Chernobyl" 2019 2019)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
```plantuml
|
|
224
|
+
@startuml
|
|
225
|
+
!theme plain
|
|
226
|
+
|
|
227
|
+
rectangle "orElse のフロー" {
|
|
228
|
+
card "extractYearStart rawShow" as first
|
|
229
|
+
card "extractSingleYear rawShow" as second
|
|
230
|
+
card "結果" as result
|
|
231
|
+
|
|
232
|
+
first --> result : Just の場合
|
|
233
|
+
first --> second : Nothing の場合
|
|
234
|
+
second --> result
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@enduml
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### 6.6 Maybe の主要関数
|
|
241
|
+
|
|
242
|
+
| 関数 | 説明 | 例 |
|
|
243
|
+
|------|------|-----|
|
|
244
|
+
| `fmap` / `<$>` | 値があれば変換 | `fmap (*2) (Just 5)` → `Just 10` |
|
|
245
|
+
| `>>=` | Maybe を返す関数を適用 | `Just 5 >>= \x -> Just (x * 2)` → `Just 10` |
|
|
246
|
+
| `<\|>` | Nothing なら代替を使用 | `Nothing <\|> Just 5` → `Just 5` |
|
|
247
|
+
| `fromMaybe` | Nothing ならデフォルト値 | `fromMaybe 0 Nothing` → `0` |
|
|
248
|
+
| `maybeToList` | List に変換 | `maybeToList (Just 5)` → `[5]` |
|
|
249
|
+
| `catMaybes` | Just だけ抽出 | `catMaybes [Just 1, Nothing, Just 3]` → `[1,3]` |
|
|
250
|
+
|
|
251
|
+
```haskell
|
|
252
|
+
import Data.Maybe
|
|
253
|
+
|
|
254
|
+
let year = Just 996
|
|
255
|
+
let noYear = Nothing :: Maybe Int
|
|
256
|
+
|
|
257
|
+
-- fmap / <$>
|
|
258
|
+
fmap (*2) year -- Just 1992
|
|
259
|
+
fmap (*2) noYear -- Nothing
|
|
260
|
+
(*2) <$> year -- Just 1992
|
|
261
|
+
|
|
262
|
+
-- >>= (bind)
|
|
263
|
+
year >>= \y -> Just (y * 2) -- Just 1992
|
|
264
|
+
noYear >>= \y -> Just (y * 2) -- Nothing
|
|
265
|
+
|
|
266
|
+
-- <|> (Alternative)
|
|
267
|
+
import Control.Applicative
|
|
268
|
+
year <|> Just 2020 -- Just 996
|
|
269
|
+
noYear <|> Just 2020 -- Just 2020
|
|
270
|
+
|
|
271
|
+
-- fromMaybe
|
|
272
|
+
fromMaybe 0 year -- 996
|
|
273
|
+
fromMaybe 0 noYear -- 0
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### 6.7 エラーハンドリング戦略
|
|
277
|
+
|
|
278
|
+
複数の要素をパースする場合、2つの戦略があります。
|
|
279
|
+
|
|
280
|
+
```plantuml
|
|
281
|
+
@startuml
|
|
282
|
+
!theme plain
|
|
283
|
+
|
|
284
|
+
rectangle "エラーハンドリング戦略" {
|
|
285
|
+
rectangle "Best-effort 戦略" as best {
|
|
286
|
+
card "パースできたものだけ返す"
|
|
287
|
+
card "エラーは無視"
|
|
288
|
+
card "[TvShow] を返す"
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
rectangle "All-or-nothing 戦略" as all {
|
|
292
|
+
card "全部成功するか、全部失敗"
|
|
293
|
+
card "一つでも失敗したら Nothing"
|
|
294
|
+
card "Maybe [TvShow] を返す"
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
@enduml
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
#### Best-effort 戦略
|
|
302
|
+
|
|
303
|
+
```haskell
|
|
304
|
+
parseShowsBestEffort :: [String] -> [TvShow]
|
|
305
|
+
parseShowsBestEffort rawShows =
|
|
306
|
+
concatMap (maybe [] (:[]) . parseShowSafe) rawShows
|
|
307
|
+
|
|
308
|
+
-- または catMaybes を使用
|
|
309
|
+
parseShowsBestEffort' :: [String] -> [TvShow]
|
|
310
|
+
parseShowsBestEffort' = catMaybes . map parseShowSafe
|
|
311
|
+
|
|
312
|
+
let rawShows = [ "Breaking Bad (2008-2013)"
|
|
313
|
+
, "Invalid Format"
|
|
314
|
+
, "Mad Men (2007-2015)"
|
|
315
|
+
]
|
|
316
|
+
|
|
317
|
+
parseShowsBestEffort rawShows
|
|
318
|
+
-- [TvShow "Breaking Bad" 2008 2013, TvShow "Mad Men" 2007 2015]
|
|
319
|
+
-- 無効なものは無視される
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### All-or-nothing 戦略
|
|
323
|
+
|
|
324
|
+
```haskell
|
|
325
|
+
parseShowsAllOrNothing :: [String] -> Maybe [TvShow]
|
|
326
|
+
parseShowsAllOrNothing = traverse parseShowSafe
|
|
327
|
+
|
|
328
|
+
-- 全部成功 → Just [...]
|
|
329
|
+
parseShowsAllOrNothing ["Breaking Bad (2008-2013)", "Mad Men (2007-2015)"]
|
|
330
|
+
-- Just [TvShow "Breaking Bad" 2008 2013, TvShow "Mad Men" 2007 2015]
|
|
331
|
+
|
|
332
|
+
-- 一つでも失敗 → Nothing
|
|
333
|
+
parseShowsAllOrNothing ["Breaking Bad (2008-2013)", "Invalid"]
|
|
334
|
+
-- Nothing
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## 第7章: Either 型と複合的なエラー処理
|
|
340
|
+
|
|
341
|
+
### 7.1 Maybe の限界
|
|
342
|
+
|
|
343
|
+
`Maybe` は「値があるかないか」しか表現できません。**なぜ失敗したのか**を伝えられません。
|
|
344
|
+
|
|
345
|
+
```plantuml
|
|
346
|
+
@startuml
|
|
347
|
+
!theme plain
|
|
348
|
+
|
|
349
|
+
rectangle "Maybe vs Either" {
|
|
350
|
+
rectangle "Maybe a" as opt {
|
|
351
|
+
card "Just value" as just
|
|
352
|
+
card "Nothing" as nothing
|
|
353
|
+
nothing -[hidden]-> just
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
rectangle "Either e a" as either {
|
|
357
|
+
card "Right value" as right
|
|
358
|
+
card "Left error" as left
|
|
359
|
+
left -[hidden]-> right
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
opt --> either : 進化
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
note bottom of nothing
|
|
366
|
+
失敗理由が分からない
|
|
367
|
+
end note
|
|
368
|
+
|
|
369
|
+
note bottom of left
|
|
370
|
+
エラー情報を保持できる
|
|
371
|
+
end note
|
|
372
|
+
|
|
373
|
+
@enduml
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### 7.2 Either の基本
|
|
377
|
+
|
|
378
|
+
`Either e a` は「`e` 型のエラーか、`a` 型の成功値か」を表す型です。
|
|
379
|
+
|
|
380
|
+
- `Right value`: 成功(慣例的に「正しい」= right)
|
|
381
|
+
- `Left error`: 失敗(エラー情報を保持)
|
|
382
|
+
|
|
383
|
+
```haskell
|
|
384
|
+
data Either e a = Left e | Right a
|
|
385
|
+
|
|
386
|
+
-- 使用例
|
|
387
|
+
Right 5 :: Either String Int -- 成功
|
|
388
|
+
Left "oops" :: Either String Int -- 失敗(エラーメッセージ付き)
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
**ソースファイル**: `app/haskell/src/Ch07/EitherHandling.hs`
|
|
392
|
+
|
|
393
|
+
### 7.3 Either を使ったパース
|
|
394
|
+
|
|
395
|
+
```haskell
|
|
396
|
+
extractNameE :: String -> Either String String
|
|
397
|
+
extractNameE rawShow =
|
|
398
|
+
case elemIndex '(' rawShow of
|
|
399
|
+
Just idx | idx > 0 -> Right $ trim $ take idx rawShow
|
|
400
|
+
_ -> Left $ "Can't extract name from " ++ rawShow
|
|
401
|
+
|
|
402
|
+
extractNameE "The Wire (2002-2008)" -- Right "The Wire"
|
|
403
|
+
extractNameE "(2022)" -- Left "Can't extract name from (2022)"
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### 7.4 Either を使った完全なパーサー
|
|
407
|
+
|
|
408
|
+
```haskell
|
|
409
|
+
extractYearStartE :: String -> Either String Int
|
|
410
|
+
extractYearStartE rawShow =
|
|
411
|
+
case (elemIndex '(' rawShow, elemIndex '-' rawShow) of
|
|
412
|
+
(Just bo, Just d) | d > bo + 1 ->
|
|
413
|
+
let yearStr = take (d - bo - 1) $ drop (bo + 1) rawShow
|
|
414
|
+
in maybeToEither ("Can't parse year: " ++ yearStr) (readMaybe yearStr)
|
|
415
|
+
_ -> Left $ "Can't extract start year from " ++ rawShow
|
|
416
|
+
|
|
417
|
+
extractYearStartE "The Wire (2002-2008)" -- Right 2002
|
|
418
|
+
extractYearStartE "The Wire (-2008)" -- Left "Can't extract start year from ..."
|
|
419
|
+
extractYearStartE "The Wire (oops-2008)" -- Left "Can't parse year: oops"
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### 7.5 Maybe から Either への変換
|
|
423
|
+
|
|
424
|
+
`maybeToEither` で `Maybe` を `Either` に変換できます。
|
|
425
|
+
|
|
426
|
+
```haskell
|
|
427
|
+
maybeToEither :: e -> Maybe a -> Either e a
|
|
428
|
+
maybeToEither _ (Just x) = Right x
|
|
429
|
+
maybeToEither e Nothing = Left e
|
|
430
|
+
|
|
431
|
+
let year = Just 996
|
|
432
|
+
let noYear = Nothing :: Maybe Int
|
|
433
|
+
|
|
434
|
+
maybeToEither "no year given" year -- Right 996
|
|
435
|
+
maybeToEither "no year given" noYear -- Left "no year given"
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
```plantuml
|
|
439
|
+
@startuml
|
|
440
|
+
!theme plain
|
|
441
|
+
|
|
442
|
+
rectangle "maybeToEither の動作" {
|
|
443
|
+
card "Just value" as just
|
|
444
|
+
card "Nothing" as nothing
|
|
445
|
+
|
|
446
|
+
card "Right value" as right
|
|
447
|
+
card "Left errorMsg" as left
|
|
448
|
+
|
|
449
|
+
just --> right : maybeToEither errorMsg
|
|
450
|
+
nothing --> left : maybeToEither errorMsg
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
@enduml
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### 7.6 Either による完全なパーサー
|
|
457
|
+
|
|
458
|
+
```haskell
|
|
459
|
+
parseShowE :: String -> Either String TvShow
|
|
460
|
+
parseShowE rawShow = do
|
|
461
|
+
name <- extractNameE rawShow
|
|
462
|
+
yearStart <- extractYearStartE rawShow `orElseE` extractSingleYearE rawShow
|
|
463
|
+
yearEnd <- extractYearEndE rawShow `orElseE` extractSingleYearE rawShow
|
|
464
|
+
return $ TvShow name yearStart yearEnd
|
|
465
|
+
|
|
466
|
+
parseShowE "The Wire (2002-2008)" -- Right (TvShow "The Wire" 2002 2008)
|
|
467
|
+
parseShowE "Mad Men ()" -- Left "Can't extract single year from Mad Men ()"
|
|
468
|
+
parseShowE "(2002-2008)" -- Left "Can't extract name from (2002-2008)"
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### 7.7 Either の主要関数
|
|
472
|
+
|
|
473
|
+
| 関数 | 説明 | 例 |
|
|
474
|
+
|------|------|-----|
|
|
475
|
+
| `fmap` / `<$>` | Right の値を変換 | `fmap (*2) (Right 5)` → `Right 10` |
|
|
476
|
+
| `>>=` | Right なら Either を返す関数を適用 | `Right 5 >>= \x -> Right (x * 2)` → `Right 10` |
|
|
477
|
+
| `either` | Left/Right で異なる処理 | `either show id (Right "ok")` → `"ok"` |
|
|
478
|
+
| `fromRight` | Left ならデフォルト値 | `fromRight 0 (Left "err")` → `0` |
|
|
479
|
+
| `partitionEithers` | Left と Right を分離 | `partitionEithers [Left "e", Right 1]` → `(["e"], [1])` |
|
|
480
|
+
|
|
481
|
+
```haskell
|
|
482
|
+
import Data.Either
|
|
483
|
+
|
|
484
|
+
let year = Right 996 :: Either String Int
|
|
485
|
+
let noYear = Left "no year" :: Either String Int
|
|
486
|
+
|
|
487
|
+
-- fmap / <$>
|
|
488
|
+
fmap (*2) year -- Right 1992
|
|
489
|
+
fmap (*2) noYear -- Left "no year"
|
|
490
|
+
|
|
491
|
+
-- >>= (bind)
|
|
492
|
+
year >>= \y -> Right (y * 2) -- Right 1992
|
|
493
|
+
noYear >>= \y -> Right (y * 2) -- Left "no year"
|
|
494
|
+
year >>= \_ -> Left "can't progress" -- Left "can't progress"
|
|
495
|
+
|
|
496
|
+
-- either
|
|
497
|
+
either length id year -- 996
|
|
498
|
+
either length id noYear -- 7 ("no year" の長さ)
|
|
499
|
+
|
|
500
|
+
-- fromRight
|
|
501
|
+
fromRight 0 year -- 996
|
|
502
|
+
fromRight 0 noYear -- 0
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### 7.8 音楽アーティスト検索の例
|
|
506
|
+
|
|
507
|
+
より複雑な例として、音楽アーティストの検索機能を見てみましょう。
|
|
508
|
+
|
|
509
|
+
#### 代数的データ型(ADT)によるモデリング
|
|
510
|
+
|
|
511
|
+
```haskell
|
|
512
|
+
-- 音楽ジャンル(直和型)
|
|
513
|
+
data MusicGenre
|
|
514
|
+
= HeavyMetal
|
|
515
|
+
| Pop
|
|
516
|
+
| HardRock
|
|
517
|
+
| Grunge
|
|
518
|
+
| Punk
|
|
519
|
+
deriving (Show, Eq)
|
|
520
|
+
|
|
521
|
+
-- 場所(直和型)
|
|
522
|
+
data Location
|
|
523
|
+
= USA
|
|
524
|
+
| England
|
|
525
|
+
| Australia
|
|
526
|
+
| Canada
|
|
527
|
+
deriving (Show, Eq)
|
|
528
|
+
|
|
529
|
+
-- 活動期間(直和型)
|
|
530
|
+
data YearsActive
|
|
531
|
+
= StillActive Int -- 活動中(開始年)
|
|
532
|
+
| ActiveBetween Int Int -- 活動終了(開始年、終了年)
|
|
533
|
+
deriving (Show, Eq)
|
|
534
|
+
|
|
535
|
+
-- アーティスト(直積型)
|
|
536
|
+
data Artist = Artist
|
|
537
|
+
{ artistName :: String
|
|
538
|
+
, artistGenre :: MusicGenre
|
|
539
|
+
, artistOrigin :: Location
|
|
540
|
+
, artistYearsActive :: YearsActive
|
|
541
|
+
} deriving (Show, Eq)
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
```plantuml
|
|
545
|
+
@startuml
|
|
546
|
+
!theme plain
|
|
547
|
+
|
|
548
|
+
rectangle "代数的データ型(ADT)" {
|
|
549
|
+
rectangle "直積型(Product Type)" as product {
|
|
550
|
+
card "data ... = Constructor field1 field2"
|
|
551
|
+
card "A AND B AND C"
|
|
552
|
+
card "フィールドの組み合わせ"
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
rectangle "直和型(Sum Type)" as sum {
|
|
556
|
+
card "data ... = A | B | C"
|
|
557
|
+
card "A OR B OR C"
|
|
558
|
+
card "選択肢のいずれか"
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
note bottom of product
|
|
563
|
+
Artist = name AND genre AND origin AND yearsActive
|
|
564
|
+
end note
|
|
565
|
+
|
|
566
|
+
note bottom of sum
|
|
567
|
+
YearsActive = StillActive OR ActiveBetween
|
|
568
|
+
end note
|
|
569
|
+
|
|
570
|
+
@enduml
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### 7.9 パターンマッチング
|
|
574
|
+
|
|
575
|
+
直和型は**パターンマッチング**で処理します。
|
|
576
|
+
|
|
577
|
+
```haskell
|
|
578
|
+
wasArtistActive :: Artist -> Int -> Int -> Bool
|
|
579
|
+
wasArtistActive artist yearStart yearEnd =
|
|
580
|
+
case artistYearsActive artist of
|
|
581
|
+
StillActive since -> since <= yearEnd
|
|
582
|
+
ActiveBetween start end_ -> start <= yearEnd && end_ >= yearStart
|
|
583
|
+
|
|
584
|
+
activeLength :: Artist -> Int -> Int
|
|
585
|
+
activeLength artist currentYear =
|
|
586
|
+
case artistYearsActive artist of
|
|
587
|
+
StillActive since -> currentYear - since
|
|
588
|
+
ActiveBetween start end_ -> end_ - start
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
```plantuml
|
|
592
|
+
@startuml
|
|
593
|
+
!theme plain
|
|
594
|
+
|
|
595
|
+
rectangle "パターンマッチング" {
|
|
596
|
+
card "artistYearsActive artist" as input
|
|
597
|
+
|
|
598
|
+
rectangle "case ... of" as match_block {
|
|
599
|
+
card "StillActive since -> ..." as case1
|
|
600
|
+
card "ActiveBetween start end -> ..." as case2
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
card "結果" as result
|
|
604
|
+
|
|
605
|
+
input --> match_block
|
|
606
|
+
match_block --> result
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
note bottom
|
|
610
|
+
全てのケースを網羅する必要がある
|
|
611
|
+
(コンパイラがチェック)
|
|
612
|
+
end note
|
|
613
|
+
|
|
614
|
+
@enduml
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### 7.10 検索条件のモデリング
|
|
618
|
+
|
|
619
|
+
検索条件も ADT でモデリングできます。
|
|
620
|
+
|
|
621
|
+
```haskell
|
|
622
|
+
data SearchCondition
|
|
623
|
+
= SearchByGenre [MusicGenre]
|
|
624
|
+
| SearchByOrigin [Location]
|
|
625
|
+
| SearchByActiveYears Int Int
|
|
626
|
+
deriving (Show, Eq)
|
|
627
|
+
|
|
628
|
+
searchArtists :: [Artist] -> [SearchCondition] -> [Artist]
|
|
629
|
+
searchArtists artists conditions =
|
|
630
|
+
filter (satisfiesAll conditions) artists
|
|
631
|
+
where
|
|
632
|
+
satisfiesAll conds artist = all (satisfies artist) conds
|
|
633
|
+
|
|
634
|
+
satisfies artist (SearchByGenre genres) =
|
|
635
|
+
artistGenre artist `elem` genres
|
|
636
|
+
satisfies artist (SearchByOrigin locations) =
|
|
637
|
+
artistOrigin artist `elem` locations
|
|
638
|
+
satisfies artist (SearchByActiveYears start end_) =
|
|
639
|
+
wasArtistActive artist start end_
|
|
640
|
+
|
|
641
|
+
-- 使用例
|
|
642
|
+
let metallica = Artist "Metallica" HeavyMetal USA (StillActive 1981)
|
|
643
|
+
let madonna = Artist "Madonna" Pop USA (StillActive 1982)
|
|
644
|
+
|
|
645
|
+
searchArtists [metallica, madonna] [SearchByGenre [HeavyMetal]]
|
|
646
|
+
-- [metallica]
|
|
647
|
+
|
|
648
|
+
searchArtists [metallica, madonna] [SearchByOrigin [USA], SearchByGenre [Pop]]
|
|
649
|
+
-- [madonna]
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
### 7.11 バリデーションの例
|
|
653
|
+
|
|
654
|
+
```haskell
|
|
655
|
+
validateAge :: Int -> Either String Int
|
|
656
|
+
validateAge age
|
|
657
|
+
| age < 0 = Left "Age cannot be negative"
|
|
658
|
+
| age > 150 = Left "Age cannot be greater than 150"
|
|
659
|
+
| otherwise = Right age
|
|
660
|
+
|
|
661
|
+
validateEmail :: String -> Either String String
|
|
662
|
+
validateEmail email
|
|
663
|
+
| '@' `notElem` email = Left "Email must contain @"
|
|
664
|
+
| '.' `notElem` email = Left "Email must contain a domain"
|
|
665
|
+
| otherwise = Right email
|
|
666
|
+
|
|
667
|
+
-- 組み合わせ
|
|
668
|
+
validateUser :: Int -> String -> Either String (Int, String)
|
|
669
|
+
validateUser age email = do
|
|
670
|
+
validAge <- validateAge age
|
|
671
|
+
validEmail <- validateEmail email
|
|
672
|
+
return (validAge, validEmail)
|
|
673
|
+
|
|
674
|
+
validateUser 25 "test@example.com" -- Right (25, "test@example.com")
|
|
675
|
+
validateUser (-5) "test@example.com" -- Left "Age cannot be negative"
|
|
676
|
+
validateUser 25 "invalid" -- Left "Email must contain @"
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
---
|
|
680
|
+
|
|
681
|
+
## まとめ
|
|
682
|
+
|
|
683
|
+
### Part III で学んだこと
|
|
684
|
+
|
|
685
|
+
```plantuml
|
|
686
|
+
@startuml
|
|
687
|
+
!theme plain
|
|
688
|
+
|
|
689
|
+
rectangle "Part III: エラーハンドリング" {
|
|
690
|
+
rectangle "第6章" as ch6 {
|
|
691
|
+
card "Maybe a"
|
|
692
|
+
card "Just / Nothing"
|
|
693
|
+
card "orElse"
|
|
694
|
+
card "do 記法"
|
|
695
|
+
card "エラーハンドリング戦略"
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
rectangle "第7章" as ch7 {
|
|
699
|
+
card "Either e a"
|
|
700
|
+
card "Right / Left"
|
|
701
|
+
card "エラーメッセージの保持"
|
|
702
|
+
card "ADT(代数的データ型)"
|
|
703
|
+
card "パターンマッチング"
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
ch6 --> ch7
|
|
708
|
+
|
|
709
|
+
@enduml
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
### Maybe vs Either の使い分け
|
|
713
|
+
|
|
714
|
+
| 状況 | 使用する型 |
|
|
715
|
+
|------|------------|
|
|
716
|
+
| 値があるかないかだけが重要 | `Maybe a` |
|
|
717
|
+
| 失敗理由を伝える必要がある | `Either e a` |
|
|
718
|
+
| 検索結果が見つからない | `Maybe a` |
|
|
719
|
+
| バリデーションエラーを伝える | `Either String a` |
|
|
720
|
+
| 複数のエラー種別がある | `Either ErrorType a` |
|
|
721
|
+
|
|
722
|
+
### Scala との対応
|
|
723
|
+
|
|
724
|
+
| Scala | Haskell | 説明 |
|
|
725
|
+
|-------|---------|------|
|
|
726
|
+
| `Option[A]` | `Maybe a` | 値の有無 |
|
|
727
|
+
| `Some(x)` | `Just x` | 値がある |
|
|
728
|
+
| `None` | `Nothing` | 値がない |
|
|
729
|
+
| `Either[E, A]` | `Either e a` | 成功/失敗 |
|
|
730
|
+
| `Right(x)` | `Right x` | 成功 |
|
|
731
|
+
| `Left(e)` | `Left e` | 失敗 |
|
|
732
|
+
| `opt.getOrElse(d)` | `fromMaybe d opt` | デフォルト値 |
|
|
733
|
+
| `opt.orElse(alt)` | `opt <\|> alt` | 代替 |
|
|
734
|
+
| `opt.toRight(e)` | `maybeToEither e opt` | Maybe→Either |
|
|
735
|
+
|
|
736
|
+
### キーポイント
|
|
737
|
+
|
|
738
|
+
1. **Maybe**: 値の有無を型で表現する(Haskell には null がない)
|
|
739
|
+
2. **Either**: 成功/失敗とエラー情報を型で表現する
|
|
740
|
+
3. **do 記法**: Maybe/Either を組み合わせて使う
|
|
741
|
+
4. **orElse / <|>**: フォールバックを提供する
|
|
742
|
+
5. **ADT**: 直積型と直和型でドメインを正確にモデリング
|
|
743
|
+
6. **パターンマッチング**: 直和型を安全に処理する(網羅性チェック付き)
|
|
744
|
+
|
|
745
|
+
### 次のステップ
|
|
746
|
+
|
|
747
|
+
Part IV では、以下のトピックを学びます:
|
|
748
|
+
|
|
749
|
+
- IO モナドの導入
|
|
750
|
+
- 副作用の管理
|
|
751
|
+
- ストリーム処理
|
|
752
|
+
|
|
753
|
+
---
|
|
754
|
+
|
|
755
|
+
## 演習問題
|
|
756
|
+
|
|
757
|
+
### 問題 1: Maybe の基本
|
|
758
|
+
|
|
759
|
+
以下の関数を実装してください。
|
|
760
|
+
|
|
761
|
+
```haskell
|
|
762
|
+
safeDivide :: Int -> Int -> Maybe Int
|
|
763
|
+
safeDivide = ???
|
|
764
|
+
|
|
765
|
+
-- 期待される動作
|
|
766
|
+
safeDivide 10 2 == Just 5
|
|
767
|
+
safeDivide 10 0 == Nothing
|
|
768
|
+
safeDivide 7 2 == Just 3
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
<details>
|
|
772
|
+
<summary>解答</summary>
|
|
773
|
+
|
|
774
|
+
```haskell
|
|
775
|
+
safeDivide :: Int -> Int -> Maybe Int
|
|
776
|
+
safeDivide _ 0 = Nothing
|
|
777
|
+
safeDivide a b = Just (a `div` b)
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
</details>
|
|
781
|
+
|
|
782
|
+
### 問題 2: Maybe の合成
|
|
783
|
+
|
|
784
|
+
以下の関数を実装してください。2つの数値文字列を受け取り、その合計を返します。
|
|
785
|
+
|
|
786
|
+
```haskell
|
|
787
|
+
addStrings :: String -> String -> Maybe Int
|
|
788
|
+
addStrings = ???
|
|
789
|
+
|
|
790
|
+
-- 期待される動作
|
|
791
|
+
addStrings "10" "20" == Just 30
|
|
792
|
+
addStrings "10" "abc" == Nothing
|
|
793
|
+
addStrings "xyz" "20" == Nothing
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
<details>
|
|
797
|
+
<summary>解答</summary>
|
|
798
|
+
|
|
799
|
+
```haskell
|
|
800
|
+
import Text.Read (readMaybe)
|
|
801
|
+
|
|
802
|
+
addStrings :: String -> String -> Maybe Int
|
|
803
|
+
addStrings a b = do
|
|
804
|
+
x <- readMaybe a
|
|
805
|
+
y <- readMaybe b
|
|
806
|
+
return (x + y)
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
</details>
|
|
810
|
+
|
|
811
|
+
### 問題 3: Either によるバリデーション
|
|
812
|
+
|
|
813
|
+
以下の関数を実装してください。年齢を検証し、エラーメッセージを返します。
|
|
814
|
+
|
|
815
|
+
```haskell
|
|
816
|
+
validateAge :: Int -> Either String Int
|
|
817
|
+
validateAge = ???
|
|
818
|
+
|
|
819
|
+
-- 期待される動作
|
|
820
|
+
validateAge 25 == Right 25
|
|
821
|
+
validateAge (-5) == Left "Age cannot be negative"
|
|
822
|
+
validateAge 200 == Left "Age cannot be greater than 150"
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
<details>
|
|
826
|
+
<summary>解答</summary>
|
|
827
|
+
|
|
828
|
+
```haskell
|
|
829
|
+
validateAge :: Int -> Either String Int
|
|
830
|
+
validateAge age
|
|
831
|
+
| age < 0 = Left "Age cannot be negative"
|
|
832
|
+
| age > 150 = Left "Age cannot be greater than 150"
|
|
833
|
+
| otherwise = Right age
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
</details>
|
|
837
|
+
|
|
838
|
+
### 問題 4: パターンマッチング
|
|
839
|
+
|
|
840
|
+
以下のデータ型とパターンマッチングを使った関数を実装してください。
|
|
841
|
+
|
|
842
|
+
```haskell
|
|
843
|
+
data PaymentMethod
|
|
844
|
+
= CreditCard String String -- カード番号、有効期限
|
|
845
|
+
| BankTransfer String -- 口座番号
|
|
846
|
+
| Cash
|
|
847
|
+
deriving (Show, Eq)
|
|
848
|
+
|
|
849
|
+
describePayment :: PaymentMethod -> String
|
|
850
|
+
describePayment = ???
|
|
851
|
+
|
|
852
|
+
-- 期待される動作
|
|
853
|
+
describePayment (CreditCard "1234" "12/25") == "Credit card ending in 1234"
|
|
854
|
+
describePayment (BankTransfer "9876") == "Bank transfer to account 9876"
|
|
855
|
+
describePayment Cash == "Cash payment"
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
<details>
|
|
859
|
+
<summary>解答</summary>
|
|
860
|
+
|
|
861
|
+
```haskell
|
|
862
|
+
describePayment :: PaymentMethod -> String
|
|
863
|
+
describePayment method = case method of
|
|
864
|
+
CreditCard number _ -> "Credit card ending in " ++ number
|
|
865
|
+
BankTransfer account -> "Bank transfer to account " ++ account
|
|
866
|
+
Cash -> "Cash payment"
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
</details>
|
|
870
|
+
|
|
871
|
+
### 問題 5: all と any
|
|
872
|
+
|
|
873
|
+
以下の条件に合うユーザーを抽出する関数を実装してください。
|
|
874
|
+
|
|
875
|
+
```haskell
|
|
876
|
+
data User = User
|
|
877
|
+
{ userName :: String
|
|
878
|
+
, userEmail :: Maybe String
|
|
879
|
+
, userAge :: Int
|
|
880
|
+
} deriving (Show, Eq)
|
|
881
|
+
|
|
882
|
+
let users = [ User "Alice" (Just "alice@example.com") 25
|
|
883
|
+
, User "Bob" Nothing 30
|
|
884
|
+
, User "Charlie" (Just "charlie@test.com") 17
|
|
885
|
+
]
|
|
886
|
+
|
|
887
|
+
-- 1. メールアドレスが設定されていないか、example.com ドメインのユーザー
|
|
888
|
+
f1 :: [User] -> [User]
|
|
889
|
+
f1 = ???
|
|
890
|
+
|
|
891
|
+
-- 2. メールアドレスが設定されていて、test.com ドメインのユーザー
|
|
892
|
+
f2 :: [User] -> [User]
|
|
893
|
+
f2 = ???
|
|
894
|
+
```
|
|
895
|
+
|
|
896
|
+
<details>
|
|
897
|
+
<summary>解答</summary>
|
|
898
|
+
|
|
899
|
+
```haskell
|
|
900
|
+
import Data.List (isSuffixOf)
|
|
901
|
+
|
|
902
|
+
-- 1. メールアドレスが設定されていないか、example.com ドメイン
|
|
903
|
+
-- maybe True ... は Scala の forall に相当
|
|
904
|
+
f1 :: [User] -> [User]
|
|
905
|
+
f1 = filter (\u -> maybe True ("@example.com" `isSuffixOf`) (userEmail u))
|
|
906
|
+
-- [Alice, Bob]
|
|
907
|
+
|
|
908
|
+
-- 2. メールアドレスが設定されていて、test.com ドメイン
|
|
909
|
+
-- maybe False ... は Scala の exists に相当
|
|
910
|
+
f2 :: [User] -> [User]
|
|
911
|
+
f2 = filter (\u -> maybe False ("@test.com" `isSuffixOf`) (userEmail u))
|
|
912
|
+
-- [Charlie]
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
</details>
|