{"id":17251362,"url":"https://github.com/michalkonecny/mixed-types-num","last_synced_at":"2025-04-14T05:22:44.372Z","repository":{"id":51980602,"uuid":"62735758","full_name":"michalkonecny/mixed-types-num","owner":"michalkonecny","description":"Alternative to Haskell Prelude.Num, deriving types bottom-up","archived":false,"fork":false,"pushed_at":"2023-08-15T01:56:19.000Z","size":1760,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-25T23:02:06.826Z","etag":null,"topics":["haskell","numeric","type-classes"],"latest_commit_sha":null,"homepage":"https://hackage.haskell.org/package/mixed-types-num","language":"Haskell","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/michalkonecny.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":"2016-07-06T16:17:24.000Z","updated_at":"2024-07-20T18:27:16.308Z","dependencies_parsed_at":"2024-07-20T18:27:07.428Z","dependency_job_id":"20324e55-ae37-4cbd-a8f7-3b97f3095c99","html_url":"https://github.com/michalkonecny/mixed-types-num","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michalkonecny%2Fmixed-types-num","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michalkonecny%2Fmixed-types-num/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michalkonecny%2Fmixed-types-num/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michalkonecny%2Fmixed-types-num/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/michalkonecny","download_url":"https://codeload.github.com/michalkonecny/mixed-types-num/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248825108,"owners_count":21167435,"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":["haskell","numeric","type-classes"],"created_at":"2024-10-15T06:50:59.823Z","updated_at":"2025-04-14T05:22:44.351Z","avatar_url":"https://github.com/michalkonecny.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mixed-types-num \u003c!-- omit in toc --\u003e\n\nThis package provides a version of Prelude where\nunary and binary operations such as `not`, `+`, `==`\nhave their result type derived from the parameter type(s)\nand thus supports mixed-type arithmetic and comparisons such as:\n\n```Text\n\u003e a = [1..10]; b = [1..11]\n\u003e length a \u003e 2^((length b)/3)\n{?(prec 36): CertainFalse}\n```\n\nPartial operations such as division, sqrt and power\ndo not throw exceptions even when errors such as division by zero\noccur.  Instead, these errors are propagated bottom-up in\na bespoke error-accumulating functor from package collect-errors.\n\nThis library (as well as collect-errors) arose while developing the\n[AERN2](https://github.com/michalkonecny/aern2) library for interval and exact real computation.\nCertain aspects are specifically tailored for interval or exact real arithmetics,\nincluding three-valued numerical comparisons and distinguishing potential and certain errors.\n\nAPI documentation available on the [Hackage page](https://hackage.haskell.org/package/mixed-types-num).\n\n## Table of contents \u003c!-- omit in toc --\u003e\n\n- [1. Examples](#1-examples)\n  - [1.1. Main idea](#11-main-idea)\n  - [1.2. Dealing with numerical errors](#12-dealing-with-numerical-errors)\n  - [1.3. The generalised power operator](#13-the-generalised-power-operator)\n  - [1.4. Undecided comparisons](#14-undecided-comparisons)\n  - [1.5. Fuzzy if-then-else](#15-fuzzy-if-then-else)\n- [2. Type classes](#2-type-classes)\n- [3. Testable specifications](#3-testable-specifications)\n- [4. Limitations](#4-limitations)\n- [5. Credits](#5-credits)\n\n## 1. Examples\n\nTo replicate the examples included below, start ghci as follows:\n\n```Text\n$ stack ghci mixed-types-num:lib --no-load --ghci-options MixedTypesNumPrelude\n*MixedTypesNumPrelude\u003e\n```\n\n### 1.1. Main idea\n\nLiterals have a fixed type:\n\n```Text\n...\u003e :t 1\n... Integer\n\n...\u003e :t 1.0\n... Rational\n\n...\u003e 1 :: Rational\n... Couldn't match type ‘Integer’ with ‘GHC.Real.Ratio Integer’ ...\n```\n\nOperations permit operands of mixed types, types inferred bottom-up:\n\n```Text\n...\u003e :t 1/2\n... :: Rational\n\n...\u003e :t 1.5 * (length [[]])\n... :: Rational\n```\n\n### 1.2. Dealing with numerical errors\n\nTo avoid runtime exceptions, it is recommended to use the CN error-collecting wrapper from package [collect-errors](https://hackage.haskell.org/package/collect-errors).  \n\nAll arithmetic operations have been extended so that it is possible to have expressions that operate exclusively on CN-wrapped types:\n\n```Text\n...\u003e f (n :: CN Integer) = 1/(1/(n-1) + 1/n) :: CN Rational\n...\u003e f (cn 0)\n{{ERROR: division by 0}}\n...\u003e f (cn 1)\n{{ERROR: division by 0}}\n...\u003e f (cn 2)\n2 % 3\n```\n\nNote that the errors printed above are not exceptions, but special values.  See the [collect-errors](https://hackage.haskell.org/package/collect-errors) documentation for more details.\n\n### 1.3. The generalised power operator\n\n```Text\n...\u003e :t 2^(-2)\n... :: Rational\n\n...\u003e :t 2^2\n... :: Rational\n\n...\u003e :t round (2^2)\n... :: Integer\n\n...\u003e :t (double 2)^(1/2)\n... :: Double\n```\n\nThe following examples require also package [aern2-real](https://hackage.haskell.org/package/aern2-real).\nTo get access to this via stack, you can start ghci eg as follows:\n\n```Text\n$ stack ghci aern2-real:lib --no-load --ghci-options AERN2.Real\nAERN2.Real\u003e import MixedTypesNumPrelude\n\n...\u003e :t pi\n...  :: CReal\n\n...\u003e :t sqrt 2\n...  :: CReal\n\n...\u003e :t 2^(1/2)\n... :: CReal\n```\n\n### 1.4. Undecided comparisons\n\nComparisons involving intervals are undecided when the intervals overlap:\n\n```Text\n\u003e pi10 = pi ? (bits 10)\n\u003e pi10\n[3.1416015625 ± ~9.7656e-4 ~2^(-10)]\n\n\u003e pi10 \u003e 0\nCertainTrue\n\n\u003e pi10 == pi10\nTrueOrFalse\n```\n\nThe above equality cannot be decided since `pi10` is not a single number but a set of numbers spanning the interval and the comparison operator cannot tell if the two operands sets represent the same number or a different number.\n\nComparison involving real numbers are semi-decidable.  The result of such a comparison is a lazy Kleenean, ie an infinite sequence of Kleeneans.\nPlease see package [aern2-real](https://github.com/michalkonecny/aern2) for further details.\n\n### 1.5. Fuzzy if-then-else\n\nThis package generalises the Haskell if-then-else statement so that it admits Kleenean and lazy Kleenean conditions:\n\n```Text\n...\u003e abs1 x = max 0 (if x \u003c 0 then -x else x)\n...\u003e abs1 (pi10 - pi10)\n[0.0009765625 ± ~9.7656e-4 ~2^(-10)]\n```\n\nAlthough the condition `x \u003c 0` cannot be decided for the interval\n`pi10-pi10 = [0 ± ~1.9531e-3 ~2^(-9)]`, the if-then-else statement is resolved by computing both branches and unifying the resulting intervals.  This makes sense only if both branches compute the same number whenever the condition cannot be decided, ie when `x = 0` in this case, making the function continuous.\n\nIf we try to define a discontinuous function this way, we get an error as soon as it is detected:\n\n```Text\n...\u003e bad1 x = if x \u003c 0 then 1-x else x\n...\u003e bad1 (pi10 - pi10)\n[0.5 ± ~0.5020 ~2^(-1)]{{ERROR: numeric error: union of enclosures: not enclosing the same value}}\n```\n\nThe generalised if-then-else works also for real numbers with lazy Kleenean comparisons:\n\n```Text\n...\u003e abs1 (pi - pi)\n{?(prec 36): [0.00000000001455191522836685... ± ~1.4552e-11 ~2^(-36)]}\n```\n\n## 2. Type classes\n\nMixed-type arithmetic operations are provided via multi-parameter type classes\nand the result type is given by associated\ntype families. For example:\n\n```Haskell\n(+) :: (CanAddAsymmetric t1 t2) =\u003e t1 -\u003e t2 -\u003e AddType t1 t2\n```\n\nThe constraint `CanAdd t1 t2` is a shortcut for both\n`CanAddAsymmetric t1 t2` and `CanAddAsymmetric t2 t1`.\n\nFor convenience there are other aggregate type constraints such as\n`CanAddThis t1 t2`, which implies that the result is of type `t1`,\nand `CanAddSameType t`, which is a shortcut for `CanAddThis t t`.\n\nNotably, there are convenience classes `Ring` and `Field` as well as `OrderedRing` and `OrderedField`.\n\nFor types that instantiate Prelude classes such as `Num`, one can\ndefine instances of the new classes using the default implementation, eg:\n\n```Haskell\n{-# LANGUAGE GeneralizedNewtypeDeriving #-}\nimport MixedTypesPrelude\nimport qualified Prelude as P\n\nnewtype II = II Integer deriving (P.Eq, P.Ord, P.Num) \ninstance CanAddAsymmetric II II\n```\n\nConversely, if one defines instances such as `CanAddAsymmetric T T`,\none can then trivially define also instances `Num T` etc:\n\n```Haskell\ninstance P.Num T where\n  (+) = (+)\n  ...\n```\n\n## 3. Testable specifications\n\nThe arithmetic type classes are accompanied by generic hspec test suites,\nwhich are specialised to concrete instance types for their testing.\nThese test suites include the expected algebraic properties of operations,\nsuch as commutativity and associativity of addition.\n\n## 4. Limitations\n\n- Not all numerical operations are supported yet.\n  Eg `tan`, `atan` are missing at the moment.\n\n- Not all Prelude numerical types are supported yet.\n  Eg `Natural` and `Float` are not supported at present,\n  but `Double` is supported.\n\n- Many common operations such as `fromEnum`, `threadDelay` give or require\n  an `Int` value, which means we sometimes need to convert:\n\n  ```Text\n  threadDelay (int 1000000)\n  integer (fromEnum True)\n  ```\n\n  Prelude functions such as `take`, `!!` and `length` that use `Int` in Prelude\n  are shadowed in MixedTypesNumPrelude with more compatible/flexible versions.\n  Beware that `Data.List.length` clashes with `length` in MixedTypesNumPrelude.\n\n- Inferred types can be very large. Eg for `f a b c = sqrt (a + b * c + 1)` the inferred type is:\n\n    ```Haskell\n    f :: (CanSqrt (AddType (AddType t2 (MulType t3 t4)) Integer),\n        CanAddAsymmetric (AddType t2 (MulType t3 t4)) Integer,\n        CanAddAsymmetric t2 (MulType t3 t4), CanMulAsymmetric t3 t4) =\u003e\n        t2\n        -\u003e t3\n        -\u003e t4\n        -\u003e SqrtType (AddType (AddType t2 (MulType t3 t4)) Integer)\n    ```\n\n## 5. Credits\n\nThe idea of having numeric expressions in Haskell with types\nderived bottom-up was initially suggested and implemented by Pieter Collins.\nThis version is a fresh rewrite by Michal Konečný.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichalkonecny%2Fmixed-types-num","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmichalkonecny%2Fmixed-types-num","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichalkonecny%2Fmixed-types-num/lists"}