{"id":15066386,"url":"https://github.com/melbournedeveloper/nadz","last_synced_at":"2025-04-10T16:51:12.822Z","repository":{"id":199745527,"uuid":"703737434","full_name":"MelbourneDeveloper/nadz","owner":"MelbourneDeveloper","description":"Carefully crafted monads, such as Result and Option for exhaustive pattern matching in Dart.","archived":false,"fork":false,"pushed_at":"2024-06-15T06:46:44.000Z","size":352,"stargazers_count":4,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-09T21:12:14.633Z","etag":null,"topics":["algebraic-data-types","dart","flutter","monads","result-object"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/nadz","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MelbourneDeveloper.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-11T20:12:16.000Z","updated_at":"2025-02-13T07:55:24.000Z","dependencies_parsed_at":"2023-10-12T03:24:51.402Z","dependency_job_id":"a0c9c925-f3f5-4a63-b9fb-ffd862afceab","html_url":"https://github.com/MelbourneDeveloper/nadz","commit_stats":null,"previous_names":["melbournedeveloper/nadz"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MelbourneDeveloper%2Fnadz","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MelbourneDeveloper%2Fnadz/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MelbourneDeveloper%2Fnadz/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MelbourneDeveloper%2Fnadz/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MelbourneDeveloper","download_url":"https://codeload.github.com/MelbourneDeveloper/nadz/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248255943,"owners_count":21073423,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algebraic-data-types","dart","flutter","monads","result-object"],"created_at":"2024-09-25T01:06:58.500Z","updated_at":"2025-04-10T16:51:12.804Z","avatar_url":"https://github.com/MelbourneDeveloper.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nadz\n\nCarefully crafted monads, such as `Result` and `Option` for exhaustive pattern matching in Dart.\n\n## Introduction\nThis library has a modern collection of monads and operators for Dart. It is inspired by the elegance of languages like F# and Haskell. The library is simple, expressive, and easy to use. It leverages the recent addition of the [`sealed` class modifier](https://dart.dev/language/class-modifiers#sealed) in Dart to provide exhaustive [pattern matching](https://dart.dev/language/patterns). This makes traversing results far easier and less error prone, particularly with [Dart's Switch Expression](https://www.christianfindlay.com/blog/dart-switch-expressions).\n\nThe types here are algebraic data types for exhaustive pattern matching.\n\nExample: \n```dart\nvoid main() {\n  final Result\u003cint,int\u003e result = Success(42);\n  final message = result.match(\n    onSuccess: (value) =\u003e 'The answer is $value',\n    onError: (error) =\u003e 'Error: $error',\n  );\n  print(message); // The answer is 42\n}\n```\n\nOr, the equivalent with a switch expression:\n\n```dart\nvoid main() {\n  final Result\u003cint,int\u003e result = Success(42);\n  final message = switch (result) {\n    //This is pattern matching\n    Success(:final value) =\u003e 'The answer is $value',\n    Error(:final error) =\u003e 'Error: $error',\n  };\n  print(message); // The answer is 42\n}\n```\n\n## What is a Monad?\n\nA monad is a pattern that helps you deal with sequences of computations while handling side effects cleanly. You can think of it as a type of wrapper around a value that also defines how to apply operations to this value. This approach lets you chain operations together in a controlled way. It manages aspects like input/output, state management, or error handling without the risk of exceptions breaking control flow. \n\nThe class not only holds data but also strictly controls how that data is accessed, processed and transferred within your application. It ensures operations are executed in a predictable and safe manner.\n\nHave you ever made a HTTP call, but didn't quite know how to deal with the result? The call may return one JSON structure, or an error structure, or you might just get an exception. This is where the `Result` monad comes in and helps you to handle all these cases in a clean and predictable way with pattern matching.\n\n## Result Monads\n\nResult monads will help to make your code more robust and maintainable. You can wrap volatile calls in `try/catches` and return a meaningful value that has enough information to display the results to the user. The most straightforward example is HTTP calls. You can squash all the complexity into a very simple call.\n\n### Complete Example\n\nYou can run this sample in the example folder.\n\n```dart\nimport 'dart:convert';\nimport 'package:http/http.dart';\nimport 'package:nadz/nadz.dart';\n\ntypedef Post = ({\n  int userId,\n  int id,\n  String title,\n  String body,\n});\n\nextension PostExtensions on Map\u003cString, dynamic\u003e {\n  Post toPost() {\n    return (\n      userId: this['userId'],\n      id: this['id'],\n      title: this['title'],\n      body: this['body'],\n    );\n  }\n}\n\nextension ClientExtensions on Client {\n  Future\u003cResult\u003cList\u003cT\u003e, int\u003e\u003e getResult\u003cT\u003e(\n    String url, {\n    required List\u003cT\u003e Function(Iterable\u003cMap\u003cString, dynamic\u003e\u003e) onSuccess,\n  }) async {\n    try {\n      final response = await this.get(Uri.parse(url));\n      if (response.statusCode == 200) {\n        final jsonList = jsonDecode(response.body) as List\u003cdynamic\u003e;\n\n        return Success(onSuccess(jsonList.cast\u003cMap\u003cString, dynamic\u003e\u003e()));\n      }\n      return Error(response.statusCode);\n    } catch (e) {\n      return Error(500);\n    }\n  }\n}\n\nvoid main() async {\n  //Make the call\n  final result = await Client().getResult(\n    'https://jsonplaceholder.typicode.com/posts',\n    onSuccess: (jsonPosts) =\u003e\n        //Map the JSON results to a list of Posts\n        jsonPosts.map((p) =\u003e p.toPost()).toList(),\n  );\n\n  final display = switch (result) {\n    //This is the exhaustive pattern matching. We can only get results of these types\n    Success(value: final posts) =\u003e 'Fetched ${posts.length} posts successfully!'\n        '\\n${posts.map((p) =\u003e 'Title: ${p.title}\\nBody: ${p.body}\\n---').join('\\n')}',\n    Error(error: final statusCode) =\u003e\n      'Failed to fetch posts. Status code: $statusCode',\n  };\n\n  print(display);\n}\n```\n\nThe above code makes the call with the HTTP client. If there is an exception, the function will return an error result. Otherwise, it will attempt to convert the JSON to a list of posts. If successful, it will return a success result with those posts. Otherwise, the result will be an error.\n\nThen, the switch expression will match the result and display the posts if successful, or an error message if not.\n\n## Option Monad\n\nThe `Option` monad is a type that represents an optional value. It can be either `Some` or `None`. This is useful when you have a value that may or may not be present. It is an alternative to using `null` values.\n\nHere is an example:\n\n```dart\nvoid main() {\n  final Option\u003cint\u003e some = Some(42);\n  final Option\u003cint\u003e none = None();\n\n  final message = switch(some) {\n    Some(:final value) =\u003e 'The answer is $value',\n    None() =\u003e 'No answer',\n  };\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmelbournedeveloper%2Fnadz","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmelbournedeveloper%2Fnadz","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmelbournedeveloper%2Fnadz/lists"}