{"id":20225541,"url":"https://github.com/purescript/purescript-partial","last_synced_at":"2026-02-16T17:02:18.916Z","repository":{"id":3021376,"uuid":"48204528","full_name":"purescript/purescript-partial","owner":"purescript","description":"Utilities for working with partial functions","archived":false,"fork":false,"pushed_at":"2025-12-27T17:40:21.000Z","size":29,"stargazers_count":15,"open_issues_count":0,"forks_count":16,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-02-01T22:54:12.267Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"PureScript","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/purescript.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}},"created_at":"2015-12-17T23:54:25.000Z","updated_at":"2025-12-27T17:40:26.000Z","dependencies_parsed_at":"2022-08-07T02:00:45.036Z","dependency_job_id":null,"html_url":"https://github.com/purescript/purescript-partial","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/purescript/purescript-partial","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript%2Fpurescript-partial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript%2Fpurescript-partial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript%2Fpurescript-partial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript%2Fpurescript-partial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/purescript","download_url":"https://codeload.github.com/purescript/purescript-partial/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript%2Fpurescript-partial/sbom","scorecard":{"id":749978,"data":{"date":"2025-08-11","repo":{"name":"github.com/purescript/purescript-partial","commit":"0fa0646f5ea1ec5f0c46dcbd770c705a6c9ad3ec"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.9,"checks":[{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":5,"reason":"Found 11/20 approved changesets -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/purescript/purescript-partial/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/purescript/purescript-partial/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/purescript/purescript-partial/ci.yml/master?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/ci.yml:25","Warn: npmCommand not pinned by hash: .github/workflows/ci.yml:26","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   2 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: BSD 3-Clause \"New\" or \"Revised\" License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 26 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-22T20:01:19.710Z","repository_id":3021376,"created_at":"2025-08-22T20:01:19.710Z","updated_at":"2025-08-22T20:01:19.710Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29513433,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-16T09:05:14.864Z","status":"ssl_error","status_checked_at":"2026-02-16T08:55:59.364Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2024-11-14T07:13:22.205Z","updated_at":"2026-02-16T17:02:18.910Z","avatar_url":"https://github.com/purescript.png","language":"PureScript","readme":"# purescript-partial\n\n[![Latest release](http://img.shields.io/github/release/purescript/purescript-partial.svg)](https://github.com/purescript/purescript-partial/releases)\n[![Build status](https://github.com/purescript/purescript-partial/workflows/CI/badge.svg?branch=master)](https://github.com/purescript/purescript-partial/actions?query=workflow%3ACI+branch%3Amaster)\n[![Pursuit](https://pursuit.purescript.org/packages/purescript-partial/badge)](https://pursuit.purescript.org/packages/purescript-partial)\n\nUtilities for working with partial functions.\n\n## Installation\n\n```\nspago install partial\n```\n\n## Why have a Partial type class?\n\nEvery now and then, you will want to use _partial functions;_ that is,\nfunctions which don't handle every possible case of their inputs. For example,\nthere is a function `fromJust :: ∀ a. Partial ⇒ Maybe a → a` in `Data.Maybe`,\nwhich gives you the value inside a `Just` value, or throws an error if given\n`Nothing`.\n\nIt's important that types tell the truth wherever possible, because this is a\nlarge part of what allows us to understand PureScript code easily and refactor\nit fearlessly. However, in certain contexts, you know that e.g. an `Either`\nvalue is always going to be `Right`, but you can't prove that to the type\nchecker, and so you want an escape hatch so that you can write a function that\ndoesn't have to deal with the `Left` case. This is often the case when\nperformance is important, for instance.\n\nPreviously, partial functions have been indicated by putting the word \"unsafe\"\nat the start of their names, or by putting them in an \"Unsafe\" module. For\ninstance, there was previously an `unsafeIndex` function in\n`Data.Array.Unsafe`, and `fromJust` used to be in `Data.Maybe.Unsafe`. However,\nthis is not ideal, because the fact that these functions are partial, and\ntherefore unsafe if used carelessly, does not appear in the type. Consequently,\nthere is little to stop you from using it in an inappropriate manner by\naccident.\n\nThe Partial type class allows us to put this information back into the types,\nand thereby allows us to clearly demarcate which parts of your code are\nresponsible for making sure that unsafe functions are used in a safe manner.\n\n## I just want to use a partial function, please\n\nIf you try to just use a partial function, you'll most likely get an error\nabout no instance being found for the `Partial` class. Take this program, for\ninstance:\n\n```purescript\nmodule Main where\n\nimport Prelude\nimport Data.Maybe (Maybe(..), fromJust)\nimport Effect (Effect)\nimport Effect.Console (logShow)\n\nmain :: Effect Unit\nmain = logShow (fromJust (Just 3))\n```\n\nBecause `fromJust` is partial, and because the partiality hasn't been\nexplicitly handled, you'll get an error:\n\n```\nat src/Main.purs line 8, column 1 - line 8, column 56\n\n  No type class instance was found for\n\n    Prim.Partial\n```\n\n_Aside: Yes, this is not a fantastic error. It's going to get better soon._\n\nThe solution is usually to add an application of `unsafePartial` somewhere,\nlike this:\n\n```purescript\nmodule Main where\n\nimport Prelude\nimport Data.Maybe (Maybe(..), fromJust)\nimport Effect (Effect)\nimport Effect.Console (logShow)\nimport Partial.Unsafe (unsafePartial)\n\nmain :: Effect Unit\nmain = logShow (unsafePartial (fromJust (Just 3)))\n```\n\n## Where should I put unsafePartial?\n\nThe rule of thumb is to put `unsafePartial` at the level of your program such\nthat the types tell the truth, and the part of your program responsible for\nmaking sure a use of a partial function is safe is also the part where the\n`unsafePartial` is. This is perhaps best demonstrated with an example.\n\nImagine that we want to represent vectors in 3D with an array containing\nexactly 3 values (perhaps we want to use them with some other API that expects\nthis representation, and we don't want to be converting back and forth all the\ntime). In this case, we would usually use a `newtype` and avoid exporting the\nconstructor:\n\n```purescript\nmodule Data.V3\n  ( V3()\n  , makeV3\n  , runV3\n  ) where\n\nnewtype V3 = V3 (Array Number)\n\nmakeV3 :: Number -\u003e Number -\u003e Number -\u003e V3\nmakeV3 x y z = V3 [x, y, z]\n\nrunV3 :: V3 -\u003e Array Number\nrunV3 (V3 v) = v\n```\n\nThis way, all of the functions are safe; the code will guarantee that any `V3`\ndoes contain exactly 3 values (although the type checker is not aware of this).\n\nNow imagine we want to write a dot product function:\n\n```purescript\ndot :: V3 -\u003e V3 -\u003e Number\ndot (V3 [x1, x2, x3]) (V3 [y1, y2, y3]) = x1*y1 + x2*y2 + x3*y3\n```\n\nWe know this is ok, but the compiler disallows it:\n\n```\nA case expression could not be determined to cover all inputs.\nThe following additional cases are required to cover all inputs:\n\n  (V3 _) _\n  _      (V3 _)\n\nAlternatively, add a Partial constraint to the type of the enclosing value.\n\nin value declaration dot\n```\n\nIn this case, we can use `unsafePartial` to explicitly say that we don't\nactually need to worry about those other cases, and therefore we don't want to\npropagate a `Partial` constraint; users of this `dot` function should not have\nto worry about this partiality. For example:\n\n```purescript\ndot :: V3 -\u003e V3 -\u003e Number\ndot x y = Partial.Unsafe.unsafePartial (go x y)\n  where\n  go :: Partial =\u003e V3 -\u003e V3 -\u003e Number\n  go (V3 [x1, x2, x3]) (V3 [y1, y2, y3]) = x1*y1 + x2*y2 + x3*y3\n  -- This second pattern can be omitted, but provides a better error message\n  -- in case we do get an invalid argument at runtime.\n  go _ _ = Partial.crash \"Bad argument: expected exactly 3 elements.\"\n```\n\nThe `unsafePartial` function comes from the `Partial.Unsafe` module, in the\n`purescript-partial` package.\n\nIn this case, we could also use `Partial.Unsafe.unsafeCrashWith`:\n\n```purescript\ndot :: V3 -\u003e V3 -\u003e Number\ndot (V3 [x1, x2, x3]) (V3 [y1, y2, y3]) = x1*y1 + x2*y2 + x3*y3\ndot _ _ = unsafeCrashWith \"Bad argument: expected exactly 3 elements.\"\n```\n\nBoth implementations will behave in the same way.\n\nIn this case, we know our `dot` implementation is fine, and so users of it\nshould not have to worry about its partiality, so it makes sense to avoid\npropagating the constraint. Now, we will see another case where a `Partial`\nconstraint _should_ be propagated.\n\nLet us suppose we want a `foldr1` function, which works in a very similar way\nto `foldr` on Lists, except that it doesn't require an initial value to be\npassed, and instead requires that the list argument contains at least one\nelement.\n\nWe can implement it like this:\n\n```purescript\nfoldr1 f (Cons x xs) = foldr f x xs\n```\n\nThe compiler infers the correct type here, which is:\n\n```purescript\nfoldr1 :: forall a. Partial =\u003e (a -\u003e a -\u003e a) -\u003e List a -\u003e a\n```\n\nNow imagine we want a version of `Data.Foldable.minimum` which returns an `a`\ninstead of a `Maybe a`, and is therefore partial. We can implement it in terms\nof our new `foldr1` function:\n\n```purescript\nminimumP = foldr1 min\n```\n\nAgain, the compiler infers the correct type:\n\n```purescript\nminimumP :: forall a. Partial =\u003e Ord a =\u003e List a -\u003e a\n```\n\nNotice that the `Partial` constraint is automatically propagated to the\n`minimumP` function because of the use of another partial function in its\ndefinition, namely `foldr1`. In this case, this is what we want; we should\npropagate the `Partial` constraint, because it is still the caller's\nresponsibility to make sure they supply a non-empty list.\n\nSo hopefully it is now clear why this partiality checking is implemented in\nterms of a type class: it allows us to elegantly reuse existing machinery in\nthe type checker in order to check that a Partial constraint is either\nexplictly handled or propagated. This should help ensure that when you're\nreading the code a few months later, it remains clear which part of the code is\nresponsible for ensuring that any assumed invariants which cannot be encoded in\nthe type system do hold.\n\n## API Documentation\n\n- API documentation is [published on Pursuit](http://pursuit.purescript.org/packages/purescript-partial).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurescript%2Fpurescript-partial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpurescript%2Fpurescript-partial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurescript%2Fpurescript-partial/lists"}