{"id":13681526,"url":"https://github.com/kowainik/trial","last_synced_at":"2025-08-24T17:41:33.568Z","repository":{"id":47988778,"uuid":"266171013","full_name":"kowainik/trial","owner":"kowainik","description":"⚖️ Trial Data Type","archived":false,"fork":false,"pushed_at":"2025-06-13T12:35:01.000Z","size":101,"stargazers_count":21,"open_issues_count":3,"forks_count":9,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-08-01T12:39:54.624Z","etag":null,"topics":["data-structures","hacktoberfest","haskell","haskell-library"],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kowainik.png","metadata":{"funding":{"ko_fi":"kowainik","github":["vrom911"]},"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-22T17:36:59.000Z","updated_at":"2025-06-13T12:35:06.000Z","dependencies_parsed_at":"2024-05-11T17:56:21.858Z","dependency_job_id":null,"html_url":"https://github.com/kowainik/trial","commit_stats":{"total_commits":39,"total_committers":4,"mean_commits":9.75,"dds":0.4358974358974359,"last_synced_commit":"4001793963a3ec74fc6a29bd99cee329c2db8754"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kowainik/trial","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kowainik%2Ftrial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kowainik%2Ftrial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kowainik%2Ftrial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kowainik%2Ftrial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kowainik","download_url":"https://codeload.github.com/kowainik/trial/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kowainik%2Ftrial/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271915890,"owners_count":24843190,"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","status":"online","status_checked_at":"2025-08-24T02:00:11.135Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["data-structures","hacktoberfest","haskell","haskell-library"],"created_at":"2024-08-02T13:01:31.930Z","updated_at":"2025-08-24T17:41:33.550Z","avatar_url":"https://github.com/kowainik.png","language":"Haskell","funding_links":["https://ko-fi.com/kowainik","https://github.com/sponsors/vrom911"],"categories":["Haskell"],"sub_categories":[],"readme":"# trial\n\n[![GitHub CI](https://github.com/kowainik/trial/workflows/CI/badge.svg)](https://github.com/kowainik/trial/actions)\n[![Hackage](https://img.shields.io/hackage/v/trial.svg?logo=haskell)](https://hackage.haskell.org/package/trial)\n[![MPL-2.0 license](https://img.shields.io/badge/license-MPL--2.0-blue.svg)](LICENSE)\n\nThe `Trial` Data Structure is a `Either`-like structure that keeps events history\ninside. The data type allows to keep track of the `Fatality` level of each such\nevent entry (`Warning` or `Error`).\n\n## Project Structure\n\nThis is a multi-package project that has the following packages inside:\n\n| Package                      | Description                                                                                                                                                  |\n|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `trial`                      | The main package that contains the `Trial` data structure, instances and useful functions to work with the structure. |\n| `trial-optparse-applicative` | `Trial` structure integration with the [`optparse-applicative`](https://hackage.haskell.org/package/optparse-applicative) library for Command Line Interface. |\n| `trial-tomland`              | `Trial` structure integration with the [`tomland`](https://hackage.haskell.org/package/tomland) library for TOML configurations.   |\n| `trial-example`              | Example project with the usage example of the `Trial` data structure. |\n\n## How to use `trial`\n\n`trial` is compatible with the latest GHC versions starting from `8.6.5`.\n\nIn order to start using `trial` in your project, you will need to set it up with\nthe three easy steps:\n\n1. Add the dependency on `trial` in your project's `.cabal` file. For this, you\n   should modify the `build-depends` section by adding the name of this library.\n   After the adjustment, this section could look like this:\n\n   ```haskell\n   build-depends: base ^\u003e= 4.14\n                , trial ^\u003e= 0.0\n   ```\n\n2. In the module where you plan to use `Trial`, you should add the import:\n\n   ```haskell\n   import Trial (Trial (..), fiasco, prettyPrintTrial)\n   ```\n\n3. Now you can use the types and functions from the library:\n\n   ```haskell\n   main :: IO ()\n   main = putStrLn $ prettyPrintTrial $ fiasco \"This is fiasco, bro!\"\n   ```\n\n## Trial Data Structure\n\nLet's have a closer look at the `Trial` data structure.\n`Trial` is a sum type that has two constructors:\n\n  - `Fiasco` — represents the unsuccessful state similar to the `Left`\n    constructor of `Either`. However, unlike `Left`, `Fiasco` holds a list of all\n    `error`-like items that happened along the way. Each such item has a notion of\n    `Fatality` (the severity of the error). The following cases cover\n    `Fatality`:\n      + `Error` — fatal error that led to the final fatal `Fiasco`.\n      + `Warning` — non-essential error, which didn't affect the result.\n  - `Result` — represents the successful state similar to the `Right`\n    constructor of `Either`. However, unlike `Right`, `Result` keeps the list of\n    all `error`-like items that happened along the way. All error items are\n    warnings as the final result was found anyway.\n\nSchematically, `Trial` has the following internal representation:\n\n```haskell\ndata Trial e a\n           │ │\n           │ ╰╴Resulting type\n           │\n           ╰╴An error item type\n\n    -- | Unsuccessful case\n    = Fiasco (DList (Fatality, e))\n              │      │         │\n              │      │         ╰╴One error item\n              │      │\n              │      ╰╴Level of damage\n              │\n              ╰╴Efficient list-container for error type items\n\n    -- | Successful case\n    | Result (DList e) a\n              │     │  │\n              │     │  ╰╴Result\n              │     │\n              │     ╰╴One warning item\n              │\n              ╰╴Efficient list-container for warning type items\n```\n\n### `Trial` instances\n\nIn order to follow the basis idea of the data type, `Trial` uses smart\nconstructors and different instances to make the structure work the way it\nworks.\n\nHere are the main points:\n\n* All `Fiasco`s can be created only with the `Error` `Fatality` level.\n* The `Fatality` level can be eased only through the `Semigroup` appends of\n  different `Trial`s.\n* All error items in `Result` should have only `Warning` `Fatality` level. This\n  is guaranteed by the `Trial` `Semigroup` and `Applicative` instances.\n* `Semigroup` is responsible for the correct collection of history events, their\n  `Fatality` level and the final result decision.\n* `Semigroup` chooses the latest 'Result' and combines all events.\n* Think of `Semigroup` instance as of high-level combinator of your result.\n* `Applicative` is responsible for the correct combination of `Trial`s.\n* `Applicative` returns `Fiasco`, if at least one value if `Fiasco`, combine all\n  events.\n* Think of `Applicative` instance as of low-level combinator of your result on the\n  record fields level.\n* `Alternative` instance could help when you want to stop on the first\n  `Result` and get the history of all failures before it.\n* `Alternative`: return first `Result`, also combine all events for\n  all `Trial`s before this `Result`.\n\n## Tagged `Trial`\n\nAdditionally, there is a `Trial`-like data type that has a notion of the `tag`\ninside.\n\nThe main difference from `Trial` is that the resulting type contains additional\ninformation of the tag (or source it came from). The type looks like this:\n\n```haskell\ntype TaggedTrial tag a = Trial tag (tag, a)\n```\n\nDue to the described instances implementation, the tag will always be aligned\nwith the final source it came from.\n\nThe library provides different ways to add the tag:\n  * Manual with the `withTag` function\n  * Using `OverloadedLabels`and the provided `IsLabel` instance for\n    `TaggedTrial`.\n\nYou can choose the one that is more suitable for your use-case.\n\n## Usage Examples\n\nOne of the use cases when one could consider using `Trial` is the configurations\nin the application.\n\nIf you need to collect configurations from different places, combine the results\ninto a single configuration, you can find the `Trial` data structure quite\nhandy. With `trial` you can get the event history for free and also you can keep\ntrack of where the final result for each component of your configurations type\ncomes from (by using `tag` functionality).\n\nThe complete example in the `trial-example` package. It combines CLI, TOML\nconfiguration and the default options provided in the source code.\n\n| Executable | Description |\n|------------|-------------|\n| [`trial-example`](https://github.com/kowainik/trial/blob/main/trial-example/app/Main.hs) | The basic example of config problem with the usage of `TaggedTrial` |\n| [`trial-example-advanced`](https://github.com/kowainik/trial/blob/main/trial-example/app-advanced/Main.hs) | The basic example of config problem with the usage of `TaggedTrial` with the `Phase` based approach. |\n\nTo run it you can use the following command:\n\n```shell\n$ cabal run trial-example\n$ cabal run trial-example-advanced\n```\n\nFor the successful result you can use the CLI and provide necessary information\nin order to have the complete configurations:\n\n```shell\n$ cabal run trial-example -- --host=\"abc\"\n$ cabal run trial-example-advanced -- --host=\"abc\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkowainik%2Ftrial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkowainik%2Ftrial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkowainik%2Ftrial/lists"}