{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreib33b47snwczelg7lgfpfq55gebvsnvfm4sskv7gsqthk37viqfom",
    "uri": "at://did:plc:pi6woz4d47bkuws673w2il2r/app.bsky.feed.post/3mmtmsmzzjrr2"
  },
  "path": "/t/why-no-exposed-nulladdr-literal/14157#post_5",
  "publishedAt": "2026-05-27T13:11:56.000Z",
  "site": "https://discourse.haskell.org",
  "tags": [
    "@jaror"
  ],
  "textContent": "jaror:\n\n> TIL pattern synonyms can be unlifted. But then a bidirectional pattern should work:\n>\n>\n>     pattern MyNullAddr# :: MyAddr#\n>     pattern MyNullAddr# <- ((\\(WrapAddr# x) -> eqAddr# nullAddr# x) -> 1#) where\n>       MyNullAddr# = WrapAddr# nullAddr#\n>\n\nAwesome, thanks! This does spark joy.\n\ntomjaguarpaw:\n\n> I’m not sure it is fair, or at least there could in principle be an exception for values, and a newtype constructor applied to a value would be value. Maybe that adds too much extra complexity to be worth it.\n\nMy impression is that on the frontend (so more superficially than @jaror’s work above, but also more programmer-visibly) and with the exception of the `nullAddr#` issue, a statically-known fully evaluated unlifted value should be able to be built up from literals and constructors, hence should be bindable as an implicitly bidirectional unlifted pattern synonym. `Language.Haskell.TH.Lit` already represents literals of types `Int#`, `Word#`, `Char#`, `Float#`, and `Double#` (and hopefully once `-XExtendedLiterals` is fully supported by TemplateHaskell, also `Int8#`, `Int16#`, `Int32#`, `Int64#`, `Word8#`, `Word16#`, `Word32#`, and `Word64#`—maybe even eventually SIMD literals, although those aren’t currently supported by `-XExtendedLiterals` either), so in cases where the literal value is the result of a nontrivial computation one can do something like\n\n\n    {-# LANGUAGE Haskell2010 #-}\n\n    module MyInt.TH where\n\n    {- | Here because of the stage restriction -}\n    complicated :: Integer -> Integer\n    complicated = \\ n -> product [ 1 .. n ]\n\n    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n    {-# LANGUAGE Haskell2010\n      , GADTSyntax\n      , MagicHash\n      , PatternSynonyms\n      , UnliftedNewtypes\n      , TemplateHaskell\n    #-}\n\n    module MyInt where\n\n    import GHC.Exts\n    import Language.Haskell.TH\n    import MyInt.TH\n\n    newtype MyInt# where\n        WrapInt# :: Int# -> MyInt#\n\n    data MyInt where\n        MyI# :: Int# -> MyInt\n\n    {- |  Binds 'WrapInt# 2432902008176640000#' as a pattern -}\n    $(pure $\n        let nm = mkName \"Fac20Int#\"\n            n = complicated 20\n        in  [ PatSynD\n                ( nm )\n                ( PrefixPatSyn [ ] )\n                ( ImplBidir )\n                ( ConP\n                    ( 'WrapInt# )\n                    [ ]\n                    [ LitP ( IntPrimL n ) ] )\n            , PatSynSigD\n                ( nm )\n                ( ConT ''MyInt# ) ]\n      )\n\n    {- |  Binds 'MyI# 2432902008176640000#' as a value -}\n    fac20Int :: MyInt\n    fac20Int = $(pure $\n        let n = complicated 20\n        in  AppE\n              ( ConE 'MyI# )\n              ( LitE ( IntPrimL n ) )\n      )\n\n",
  "title": "Why no exposed `NullAddr#` literal?"
}