{"id":18464753,"url":"https://github.com/norfairking/haskell-wat","last_synced_at":"2025-04-29T19:50:10.075Z","repository":{"id":50083936,"uuid":"187423411","full_name":"NorfairKing/haskell-WAT","owner":"NorfairKing","description":"A collection of Haskell's WATs","archived":false,"fork":false,"pushed_at":"2025-01-22T17:24:29.000Z","size":19,"stargazers_count":92,"open_issues_count":0,"forks_count":3,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-02-16T17:24:03.615Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NorfairKing.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2019-05-19T02:02:02.000Z","updated_at":"2025-02-06T18:14:15.000Z","dependencies_parsed_at":"2023-11-24T09:46:16.297Z","dependency_job_id":null,"html_url":"https://github.com/NorfairKing/haskell-WAT","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NorfairKing%2Fhaskell-WAT","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NorfairKing%2Fhaskell-WAT/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NorfairKing%2Fhaskell-WAT/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NorfairKing%2Fhaskell-WAT/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NorfairKing","download_url":"https://codeload.github.com/NorfairKing/haskell-WAT/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251372467,"owners_count":21578964,"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":[],"created_at":"2024-11-06T09:10:57.366Z","updated_at":"2025-04-28T19:01:49.882Z","avatar_url":"https://github.com/NorfairKing.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Haskell WATs\n\nThis is a collection of Haskell's WATs\n\nSee also [the list of dangerous functions](https://github.com/NorfairKing/haskell-dangerous-functions).\n\n## Read instances for integral types\n\nThese instances use [`fromIntegral`, which is a dangerous function](https://github.com/NorfairKing/haskell-dangerous-functions#fromintegral-and-frominteger).\n\n```\nghci\u003e import Data.Word\nghci\u003e import Data.Int\nghci\u003e read \"128\" :: Int8\n-128\nghci\u003e read \"256\" :: Word8\n0\nghci\u003e read \"60000\" :: Int16\n-5536\nghci\u003e read \"70000\" :: Word16\n4464\nghci\u003e read \"2147483649\" :: Int32\n-2147483647\nghci\u003e read \"42147483649\" :: Word32\n3492777985\nghci\u003e read \"5000000000000000000000\" :: Int64\n932356024711512064\nghci\u003e read \"18446744073709551617\" :: Word\n1\nghci\u003e read \"18446744073709551617\" :: Int\n1\nghci\u003e read \"28446744073709551617\" :: Word\n10000000000000000001\nghci\u003e read \"-1\" :: Word8\n255\nghci\u003e read \"-1\" :: Word16\n65535\nghci\u003e read \"-1\" :: Word32\n4294967295\nghci\u003e read \"-1\" :: Word64\n18446744073709551615\nghci\u003e read \"-1\" :: Word\n18446744073709551615\n```\n\nThere's a [GHC issue about fixing this](https://gitlab.haskell.org/ghc/ghc/-/issues/24216).\n\n## Eq Double\n\n``` haskell\nPrelude\u003e let nan = read \"NaN\" :: Double\nPrelude\u003e nan == nan\nFalse\nPrelude\u003e nan /= nan\nTrue\n```\n\nYou might think \"That's just the way IEEE 754 floating point numbers work.\", and I would agree with you if [Rust hadn't done it right](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html).\n\nThis problem has some interesting nasty side-effects:\n\n* You can never use `Double` as the key in a Map:\n\n```\nPrelude\u003e import qualified Data.Map as M\nPrelude M\u003e M.fromList [(nan, 1), (nan, 2)]\nfromList [(NaN,1),(NaN,2)]\n```\n\n* You can never use `Double` as the key in a HashMap:\n\n```\nPrelude\u003e import qualified Data.HashMap.Strict as HM\nPrelude HM\u003e HM.fromList [(nan, 1), (nan, 2)]\nfromList [(NaN,1),(NaN,2)]\n```\n\n## Ord Double\n\n``` haskell\nPrelude\u003e let nan = read \"NaN\" :: Double\nPrelude\u003e nan \u003e= nan\nFalse\nPrelude\u003e nan \u003e nan\nFalse\nPrelude\u003e nan \u003c= nan\nFalse\nPrelude\u003e nan \u003c nan\nFalse\nPrelude\u003e compare nan nan\nGT\n```\n\nYou might think \"That's just the way IEEE 754 floating point numbers work.\", and I would agree with you if [Rust hadn't done it right](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html).\nIn particular, `compare nan nan` being `GT` is certainly inconsistent.\n\n## Real Double\n\n``` Haskell\nPrelude\u003e let nan = read \"NaN\" :: Double\nPrelude\u003e toRational nan\n(-269653970229347386159395778618353710042696546841345985910145121736599013708251444699062715983611304031680170819807090036488184653221624933739271145959211186566651840137298227914453329401869141179179624428127508653257226023513694322210869665811240855745025766026879447359920868907719574457253034494436336205824) % 1\nPrelude\u003e realToFrac nan -- With -O0\n-Infinity\nPrelude\u003e realToFrac nan\nNaN\n```\n\n## RealFrac Double\n\n```\nPrelude\u003e let nan = read \"NaN\" :: Double\nPrelude\u003e properFraction nan\n(-269653970229347386159395778618353710042696546841345985910145121736599013708251444699062715983611304031680170819807090036488184653221624933739271145959211186566651840137298227914453329401869141179179624428127508653257226023513694322210869665811240855745025766026879447359920868907719574457253034494436336205824,0.0)\ntruncate nan\n-269653970229347386159395778618353710042696546841345985910145121736599013708251444699062715983611304031680170819807090036488184653221624933739271145959211186566651840137298227914453329401869141179179624428127508653257226023513694322210869665811240855745025766026879447359920868907719574457253034494436336205824\nPrelude\u003e round nan\n-269653970229347386159395778618353710042696546841345985910145121736599013708251444699062715983611304031680170819807090036488184653221624933739271145959211186566651840137298227914453329401869141179179624428127508653257226023513694322210869665811240855745025766026879447359920868907719574457253034494436336205824\nPrelude\u003e floor nan\n-269653970229347386159395778618353710042696546841345985910145121736599013708251444699062715983611304031680170819807090036488184653221624933739271145959211186566651840137298227914453329401869141179179624428127508653257226023513694322210869665811240855745025766026879447359920868907719574457253034494436336205824\nPrelude\u003e ceiling nan\n-269653970229347386159395778618353710042696546841345985910145121736599013708251444699062715983611304031680170819807090036488184653221624933739271145959211186566651840137298227914453329401869141179179624428127508653257226023513694322210869665811240855745025766026879447359920868907719574457253034494436336205824\nPrelude\u003e properFraction nan :: (Int, Double)\n(0,0.0)\nPrelude\u003e round nan :: Int\n0\nPrelude\u003e floor nan :: Int\n0\nPrelude\u003e ceiling nan :: Int\n0\n```\n#### Rounding\n```haskell\nmain = print (round (1e206 :: Double) :: Int)\n```\nDepending on the ghc optimization flag double rounding overflows differently:\n```haskell\n$ ghc round.hs \u0026\u0026 ./round\n[1 of 1] Compiling Main             ( round.hs, round.o )\nLinking round ...\n0\n$ ghc -O1 round.hs \u0026\u0026 ./round\n[1 of 1] Compiling Main             ( round.hs, round.o ) [Optimisation flags changed]\nLinking round ...\n-9223372036854775808\n```\nThis is because when optimization is turned on there are rewrite rules that use `double2Int` implemented in C. Therefore all of these potentially have a problem like that:\n```\n{-# RULES\n\"properFraction/Double-\u003eInteger\"    properFraction = properFractionDoubleInteger\n\"truncate/Double-\u003eInteger\"          truncate = truncateDoubleInteger\n\"floor/Double-\u003eInteger\"             floor = floorDoubleInteger\n\"ceiling/Double-\u003eInteger\"           ceiling = ceilingDoubleInteger\n\"round/Double-\u003eInteger\"             round = roundDoubleInteger\n\"properFraction/Double-\u003eInt\"        properFraction = properFractionDoubleInt\n\"truncate/Double-\u003eInt\"              truncate = double2Int\n\"floor/Double-\u003eInt\"                 floor = floorDoubleInt\n\"ceiling/Double-\u003eInt\"               ceiling = ceilingDoubleInt\n\"round/Double-\u003eInt\"                 round = roundDoubleInt\n  #-}\n```\n\n## Num Int\n\n```\nPrelude\u003e minBound * (-1) :: Int\n-9223372036854775808\nPrelude\u003e abs (minBound :: Int)\n-9223372036854775808\nPrelude\u003e minBound `div` (-1) :: Int\n*** Exception: arithmetic overflow\nPrelude\u003e minBound `quot` (-1) :: Int\n*** Exception: arithmetic overflow\n```\n\nDo we want modular arithmetic on `Int` or do we want to throw errors on (over|under)flow?\n\n## Enum Rational and Enum Double\n\n`Rational` is an `Enum`, which makes no sense because the `Rational` values are not enumerable in order.\nOn top of that:\n\n```\nPrelude\u003e [1..2] :: [Rational]\n[1 % 1,2 % 1]\nPrelude\u003e fromEnum (1 :: Rational)\n1\nPrelude\u003e fromEnum (1.35 :: Rational)\n1\n```\n\n`Double` can be an `Enum`, but it is implemented as a WAT:\n\n```\nPrelude\u003e [1..2] :: [Double]\n[1.0,2.0]\nPrelude\u003e fromEnum (1 :: Double)\n1\nPrelude\u003e fromEnum (1.35 :: Double)\n1\n```\n\nThis gets programmers into problem because types like `Micro` _are_ implemented correctly:\n\n```\nPrelude\u003e Import Data.Fixed\nPrelude Data.Fixed\u003e length ([1..2] :: [Micro])\n1000001\n```\n\n## `Ratio` with fixed-size underlying types\n\n(Recall (from the docs); \"The numerator and denominator have no common factor and the denominator is positive.\")\n\nYou can end up with invalid `Ratio` values using `Num` functions:\n\n```\nPrelude Data.Int Data.Ratio\u003e let r = 1 % 12 :: Ratio Int8\nPrelude Data.Int Data.Ratio\u003e r - r\n0 % (-1)\nPrelude Data.Int Data.Ratio\u003e r + r\n3 % (-14)\n\u003e r * r\n1 % (-112)\n```\n\n## Do block without a monad\n\nThis 'just works':\n\n```\nmyTest :: Int\nmyTest = do\n  let x = 5\n  x\n```\n\n## Text round trip\n\n`Text` values can only contain valid Unicode, so `Char` values from U+D800 to U+DFFF are replaced by U+FFFD, the replacement character.\n\n``` hs\n\u003e\u003e\u003e any (\\ char -\u003e [char] == Text.unpack (Text.pack [char])) ['\\xd800' .. '\\xdfff']\nFalse\n```\n\nThis means that round-tripping a `String` through `Text` may not give you what you started with.\n\n``` hs\n\u003e\u003e\u003e let string = \"haskell \\xd800 wat\"\n\u003e\u003e\u003e string\n\"haskell \\55296 wat\"\n\u003e\u003e\u003e Text.pack string\n\"haskell \\65533 wat\"\n```\n\n## `Fixed` precision\n\n[`Fixed`](https://hackage.haskell.org/package/base-4.15.0.0/docs/Data-Fixed.html) data types can silently lose precision from literal values.\nFor example the `Centi` type is supposed to have one decimal of precision.\nLiterals values are truncated without warning.\n\n``` hs\n\u003e\u003e\u003e 1.21 :: Deci\n1.2\n\u003e\u003e\u003e 1.29 :: Deci\n1.2\n```\n\nThe [`overflowed-literals`](https://downloads.haskell.org/~ghc/9.0.1/docs/html/users_guide/using-warnings.html#ghc-flag--Woverflowed-literals) warning catches this for integral values.\nUnfortunately it doesn't work for fixed- or floating-point values.\n\u003chttps://gitlab.haskell.org/ghc/ghc/-/issues/13232\u003e\n\n## Foldable tuples\n\nThe WAT here is not the behaviour per se (because you can figure that out from the kind of Foldable), but rather that someone thought this instance was a good idea.\n\n```\nPrelude\u003e length ('a','b')\n1\nPrelude\u003e maximum (2,1)\n1\nPrelude\u003e minimum (1,2)\n2\nPrelude\u003e sum (2,1)\n1\nPrelude\u003e and (False, True)\nTrue\nPrelude\u003e or (True, False)\nFalse\n```\n\n## Foldable `Complex`\n\nNo one use these, as far as I can tell, so it doesn't really matter, but these are amazing.\nJust so you know, `a :+ b` is the value that represents `a + ib`.\n\n```\nPrelude Data.Complex\u003e length (1 :+ 1) -- 1 + 1i\n2\nPrelude Data.Complex\u003e null (0 :+ 0) -- 0 + 0i\nFalse\nPrelude Data.Complex\u003e sum (2 :+ 2) -- 2 + 2i\n4\nPrelude Data.Complex\u003e product (3 :+ 3) -- 3 + 3i\n9\n```\n\n### HasCallStack\n\nThe `HasCallStack` constraint can change a program's semantics based on where it is:\n\n```\nwhat :: (HasCallStack) =\u003e Int                                 \nwhat = srcLocStartCol (snd (head (getCallStack callStack)))  \n                                                              \nmain :: IO ()                                                 \nmain = print (what + what) -- Prints \"27\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnorfairking%2Fhaskell-wat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnorfairking%2Fhaskell-wat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnorfairking%2Fhaskell-wat/lists"}