packages feed

reflection 2.1.4 → 2.1.9

raw patch · 15 files changed

Files

+ .hlint.yaml view
@@ -0,0 +1,2 @@+- ignore: {name: Unused LANGUAGE pragma}+- ignore: {name: Avoid lambda}
− .travis.yml
@@ -1,161 +0,0 @@-# This Travis job script has been generated by a script via-#-#   runghc make_travis_yml_2.hs '-o' '.travis.yml' '--ghc-head' '--jobs=2' '--irc-channel=irc.freenode.org#haskell-lens' '--no-no-tests-no-bench' '--no-install-dependencies' 'cabal.project'-#-# For more information, see https://github.com/hvr/multi-ghc-travis-#-language: c-sudo: false--git:-  submodules: false  # whether to recursively clone submodules--notifications:-  irc:-    channels:-      - "irc.freenode.org#haskell-lens"-    skip_join: true-    template:-      - "\x0313reflection\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}"--cache:-  directories:-    - $HOME/.cabal/packages-    - $HOME/.cabal/store--before_cache:-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log-  # remove files that are regenerated by 'cabal update'-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx--  - rm -rfv $HOME/.cabal/packages/head.hackage--matrix:-  include:-    - compiler: "ghc-8.6.1"-      env: GHCHEAD=true-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.6.1], sources: [hvr-ghc]}}-    - compiler: "ghc-8.4.3"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}}-    - compiler: "ghc-8.2.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.2], sources: [hvr-ghc]}}-    - compiler: "ghc-8.0.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.2], sources: [hvr-ghc]}}-    - compiler: "ghc-7.10.3"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.3], sources: [hvr-ghc]}}-    - compiler: "ghc-7.8.4"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.4], sources: [hvr-ghc]}}-    - compiler: "ghc-7.6.3"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.6.3], sources: [hvr-ghc]}}-    - compiler: "ghc-7.4.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.4.2], sources: [hvr-ghc]}}-    - compiler: "ghc-7.2.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.2.2], sources: [hvr-ghc]}}-    - compiler: "ghc-7.0.4"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.0.4], sources: [hvr-ghc]}}-    - compiler: "ghc-head"-      env: GHCHEAD=true-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-head], sources: [hvr-ghc]}}--  allow_failures:-    - compiler: "ghc-head"-    - compiler: "ghc-7.0.4"-    - compiler: "ghc-7.2.2"-    - compiler: "ghc-8.6.1"--before_install:-  - HC=${CC}-  - HCPKG=${HC/ghc/ghc-pkg}-  - unset CC-  - ROOTDIR=$(pwd)-  - mkdir -p $HOME/.local/bin-  - "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"-  - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))-  - echo $HCNUMVER--install:-  - cabal --version-  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"-  - BENCH=${BENCH---enable-benchmarks}-  - TEST=${TEST---enable-tests}-  - HADDOCK=${HADDOCK-true}-  - UNCONSTRAINED=${UNCONSTRAINED-true}-  - NOINSTALLEDCONSTRAINTS=${NOINSTALLEDCONSTRAINTS-false}-  - GHCHEAD=${GHCHEAD-false}-  - travis_retry cabal update -v-  - "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"-  - rm -fv cabal.project cabal.project.local-  - "sed -i.bak 's/^-- jobs:.*/jobs: 2/' ${HOME}/.cabal/config"-  # Overlay Hackage Package Index for GHC HEAD: https://github.com/hvr/head.hackage-  - |-    if $GHCHEAD; then-      sed -i 's/-- allow-newer: .*/allow-newer: *:base/' ${HOME}/.cabal/config-      for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i "s/allow-newer: /allow-newer: *:$pkg, /" ${HOME}/.cabal/config; done--      echo 'repository head.hackage'                                                        >> ${HOME}/.cabal/config-      echo '   url: http://head.hackage.haskell.org/'                                       >> ${HOME}/.cabal/config-      echo '   secure: True'                                                                >> ${HOME}/.cabal/config-      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> ${HOME}/.cabal/config-      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> ${HOME}/.cabal/config-      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> ${HOME}/.cabal/config-      echo '   key-threshold: 3'                                                            >> ${HOME}/.cabal.config--      grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'--      cabal new-update head.hackage -v-    fi-  - grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'-  - "printf 'packages: \".\"\\n' > cabal.project"-  - touch cabal.project.local-  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"-  - cat cabal.project || true-  - cat cabal.project.local || true-  - if [ -f "./configure.ac" ]; then-      (cd "." && autoreconf -i);-    fi-  - rm -f cabal.project.freeze-  - rm -rf .ghc.environment.* "."/dist-  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)--# Here starts the actual work to be performed for the package under test;-# any command which exits with a non-zero exit code causes the build to fail.-script:-  # test that source-distributions can be generated-  - (cd "." && cabal sdist)-  - mv "."/dist/reflection-*.tar.gz ${DISTDIR}/-  - cd ${DISTDIR} || false-  - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;-  - "printf 'packages: reflection-*/*.cabal\\n' > cabal.project"-  - touch cabal.project.local-  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"-  - cat cabal.project || true-  - cat cabal.project.local || true--  # build & run tests, build benchmarks-  - cabal new-build -w ${HC} ${TEST} ${BENCH} all--  # cabal check-  - (cd reflection-* && cabal check)--  # haddock-  - rm -rf ./dist-newstyle-  - if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi--  # Build without installed constraints for packages in global-db-  - if $UNCONSTRAINED; then rm -f cabal.project.local; echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks all; else echo "Not building without installed constraints"; fi--# REGENDATA ["-o",".travis.yml","--ghc-head","--jobs=2","--irc-channel=irc.freenode.org#haskell-lens","--no-no-tests-no-bench","--no-install-dependencies","cabal.project"]-# EOF
CHANGELOG.markdown view
@@ -1,3 +1,23 @@+# 2.1.9 [2024.12.04]+* Drop support for pre-8.0 versions of GHC.++# 2.1.8 [2024.05.04]+* Fix a memory leak in `reifyTypeable`.++# 2.1.7 [2023.02.28]+* When building with `base-4.18` (GHC 9.6) or later, implement `reifyNat` and+  `reifySymbol` using the API provided by `GHC.TypeLits` instead of resorting+  to `unsafeCoerce`.++# 2.1.6 [2020.05.16]+* Fix a bug in which `give` (and possibly `reify`, `reifyNat`, and+  `reifySymbol`) could be unsoundly inlined by GHC 8.10 or older to produce+  incorrect runtime results.++# 2.1.5 [2019.08.27]+* Fix a bug in which `reifyNat` would yield incorrect results for very large+  `Integer`s on GHC 8.2 or later.+ # 2.1.4 [2018.07.02] * Allow building with GHC 8.6. 
README.markdown view
@@ -1,7 +1,7 @@ reflection ========== -[![Hackage](https://img.shields.io/hackage/v/reflection.svg)](https://hackage.haskell.org/package/reflection) [![Build Status](https://secure.travis-ci.org/ekmett/reflection.png?branch=master)](http://travis-ci.org/ekmett/reflection)+[![Hackage](https://img.shields.io/hackage/v/reflection.svg)](https://hackage.haskell.org/package/reflection) [![Build Status](https://github.com/ekmett/reflection/workflows/Haskell-CI/badge.svg)](https://github.com/ekmett/reflection/actions?query=workflow%3AHaskell-CI)  This package provides an implementation of the ideas presented in [Functional Pearl: Implicit Configurations](http://okmij.org/ftp/Haskell/tr-15-04.pdf) by Oleg Kiselyov and Chung-Chieh Shan. However, the API has been implemented in a much more efficient manner. 
examples/Constraints.hs view
@@ -1,21 +1,24 @@-{-# LANGUAGE Rank2Types, TypeFamilies, TypeOperators, ConstraintKinds, PolyKinds, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, FlexibleContexts, UndecidableInstances #-}+{-# LANGUAGE Rank2Types, TypeFamilies, TypeOperators, ConstraintKinds, PolyKinds, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, FlexibleContexts, UndecidableInstances, CPP #-} module Constraints where -import Control.Newtype        -- from newtype-import Data.Constraint        -- from constraints-import Data.Constraint.Unsafe -- from constraints-import Data.Monoid            -- from base-import Data.Proxy             -- from tagged-import Data.Reflection        -- from reflection+import Control.Newtype.Generics -- from newtype-generics+import Data.Constraint          -- from constraints+import Data.Constraint.Unsafe   -- from constraints+import Data.Proxy               -- from tagged+import Data.Reflection          -- from reflection+#if !(MIN_VERSION_base(4,11,0))+import Data.Semigroup           -- from semigroups+#endif --- | Values in our dynamically constructed monoid over 'a'+-- | Values in our dynamically constructed monoid over @a@ newtype Lift (p :: * -> Constraint) (a :: *) (s :: *) = Lift { lower :: a }  class ReifiableConstraint p where   data Def (p :: * -> Constraint) (a :: *)   reifiedIns :: Reifies s (Def p a) :- p (Lift p a s) -instance Newtype (Lift p a s) a where+instance Newtype (Lift p a s) where+  type O (Lift p a s) = a   pack = Lift   unpack = lower @@ -42,8 +45,11 @@   data Def Monoid a = Monoid { mappend_ :: a -> a -> a, mempty_ :: a }   reifiedIns = Sub Dict +instance Reifies s (Def Monoid a) => Semigroup (Lift Monoid a s) where+  a <> b             = Lift $ mappend_ (reflect a) (lower a) (lower b)+ instance Reifies s (Def Monoid a) => Monoid (Lift Monoid a s) where-  mappend a b        = Lift $ mappend_ (reflect a) (lower a) (lower b)+  mappend            = (<>)   mempty = a where a = Lift $ mempty_ (reflect a)  data ClassProxy (p :: * -> Constraint) = ClassProxy
examples/FromJSON.hs view
@@ -1,27 +1,30 @@ -- Example of a dynamically generated FromJSON instance. ----- Can be useful when one needs to use a function with a --- FromJSON constraint, but some detail about the +-- Can be useful when one needs to use a function with a+-- FromJSON constraint, but some detail about the -- conversion from JSON is not known until runtime.+{-# LANGUAGE CPP #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE OverloadedStrings #-} -import Data.Reflection -- from reflection-import Data.Monoid     -- from base-import Data.Proxy      -- from tagged-import Data.Text       -- from text-import Data.Monoid  -import Data.Aeson      -- from aeson     +import Data.Aeson             -- from aeson+import qualified Data.Aeson.Key as Key import Data.Aeson.Types (Parser)+import Data.Proxy             -- from tagged+import Data.Reflection        -- from reflection+#if !(MIN_VERSION_base(4,11,0))+import Data.Semigroup         -- from base+#endif+import Data.Text (Text, pack) -- from text  import Control.Applicative  -- These imports are only for constructing the example value-import Control.Lens (preview)           -- from lens-import Data.Aeson.Lens (_Value,_String) -- form lens-aeson+import Lens.Micro.Aeson (_Value)   -- form microlens-aeson+import Lens.Micro.Extras (preview) -- from microlens  data Foo = Foo     {@@ -31,19 +34,20 @@  fooParser :: Text -> Object -> Parser Foo fooParser prefix o = do-    Foo <$> o .: (prefix <> "field1") <*> o .: (prefix <> "field2")+    Foo <$> o .: (Key.fromText prefix <> "field1") <*> o .: (Key.fromText prefix <> "field2")  -- A wrapper over Foo carrying a phantom type s newtype J a s = J { runJ :: a }- --- If the phantom type s reifies the parsing function, we can --- use reflect to recover the function and implement ++-- If the phantom type s reifies the parsing function, we can+-- use reflect to recover the function and implement -- our FromJSON instance for J. instance Reifies s (Object -> Parser a) => FromJSON (J a s) where     parseJSON (Object v) = J <$> reflect (Proxy :: Proxy s) v- +    parseJSON _          = empty+ -- Convince the compiler that the phantom type in the proxy--- supplied by reify is the same as the phantom type in J. +-- supplied by reify is the same as the phantom type in J. -- -- Otherwise the FromJSON instance for J won't kick in. asProxyJ :: Proxy s -> J a s -> J a s@@ -53,18 +57,18 @@ exampleJSON = maybe Null id (preview _Value str)   where     str = "{ \"zzfield1\" : 5, \"zzfield2\" : 7 }"::Text- + main :: IO () main = do     putStrLn "Enter prefix for the fields: "     -- "zz" must be entered for the parse to succeed     prefix <- fmap pack getLine- +     -- fromJSON uses the dynamically generated FromJSON instance     let result = reify (fooParser prefix) $ \proxy ->             -- We must eliminate the J newtype before returning             -- because, thanks to parametricity,             -- the phantom type cannot escape the callback.-            runJ . asProxyJ proxy <$> fromJSON exampleJSON - +            runJ . asProxyJ proxy <$> fromJSON exampleJSON+     putStrLn (show (result :: Result Foo))
examples/Monoid.hs view
@@ -1,11 +1,13 @@ {-# LANGUAGE CPP, Rank2Types, FlexibleContexts, UndecidableInstances #-} module Monoid where +import Data.Proxy      -- from tagged import Data.Reflection -- from reflection+#if !(MIN_VERSION_base(4,11,0)) import Data.Semigroup  -- from base-import Data.Proxy      -- from tagged+#endif --- | Values in our dynamically-constructed 'Monoid' over 'a'+-- | Values in our dynamically-constructed 'Monoid' over @a@ newtype M a s = M { runM :: a } deriving (Eq,Ord)  -- | A dictionary describing a 'Monoid'
examples/ReaderLike.hs view
@@ -9,7 +9,6 @@  import Data.Proxy import Data.Reflection-import Control.Applicative import System.IO  data MyConfig = MyConfig@@ -37,7 +36,7 @@   conf = reflect (Proxy :: Proxy p)  run :: forall p. (Reifies p MyConfig) => Proxy p -> IO ()-run p = do+run _ = do   d1 <- ask "Datum 1:" :: IO (Datum p)   d2 <- ask "Datum 2:" :: IO (Datum p)   -- look ma, no plumbing@@ -66,4 +65,6 @@     where conf = reflect (Proxy :: Proxy p)   abs = undefined   signum = undefined+  (-) = undefined+  negate = undefined   fromInteger = Datum
examples/reflection-examples.cabal view
@@ -15,16 +15,19 @@                 2004 Oleg Kiselyov and Chung-chieh Shan build-type:     Simple cabal-version:  >= 1.10-tested-with:   GHC == 7.0.4-             , GHC == 7.2.2-             , GHC == 7.4.2-             , GHC == 7.6.3-             , GHC == 7.8.4-             , GHC == 7.10.3-             , GHC == 8.0.2+tested-with:   GHC == 8.0.2              , GHC == 8.2.2-             , GHC == 8.4.3-             , GHC == 8.6.1+             , GHC == 8.4.4+             , GHC == 8.6.5+             , GHC == 8.8.4+             , GHC == 8.10.7+             , GHC == 9.0.2+             , GHC == 9.2.8+             , GHC == 9.4.8+             , GHC == 9.6.6+             , GHC == 9.8.4+             , GHC == 9.10.1+             , GHC == 9.12.1  flag examples   default: True@@ -34,24 +37,28 @@     buildable:         False   exposed-modules:     Constraints                        Monoid-  build-depends:       base >= 4.8 && < 5,+  build-depends:       base >= 4.9 && < 5,                        constraints,-                       newtype,+                       newtype-generics >= 0.5.3,                        reflection,+                       semigroups,                        tagged   hs-source-dirs:      .   ghc-options:         -Wall+  if impl(ghc >= 8.6)+    ghc-options:       -Wno-star-is-type   default-language:    Haskell2010  executable reflection-from-json   if !flag(examples)     buildable:         False   main-is:             FromJSON.hs-  build-depends:       aeson,-                       base >= 4.8 && < 5,-                       lens,-                       lens-aeson,+  build-depends:       aeson >= 2 && < 2.3,+                       base >= 4.9 && < 5,+                       microlens,+                       microlens-aeson >= 2.5.1,                        reflection,+                       semigroups,                        tagged,                        text   hs-source-dirs:      .@@ -62,10 +69,12 @@   if !flag(examples)     buildable:         False   main-is:             ReaderLike.hs-  build-depends:       base >= 4.8 && < 5,+  build-depends:       base >= 4.9 && < 5,                        reflection,                        tagged   hs-source-dirs:      .   ghc-options:         -Wall -threaded -rtsopts+  if impl(ghc >= 8.6)+    ghc-options:       -Wno-star-is-type   default-language:    Haskell2010 
fast/Data/Reflection.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}@@ -6,36 +7,23 @@ {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE PatternGuards #-}+{-# LANGUAGE PolyKinds #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE ScopedTypeVariables #-}-#if __GLASGOW_HASKELL__ >= 706-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE PolyKinds #-} {-# LANGUAGE TypeOperators #-}-#define USE_TYPE_LITS 1-#endif #ifdef MIN_VERSION_template_haskell-# if __GLASGOW_HASKELL__ >= 800 -- TH-subset that works with stage1 & unregisterised GHCs {-# LANGUAGE TemplateHaskellQuotes #-}-# else-{-# LANGUAGE TemplateHaskell #-}-# endif #endif  {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE UndecidableInstances #-}  {-# OPTIONS_GHC -fno-cse #-} {-# OPTIONS_GHC -fno-full-laziness #-} {-# OPTIONS_GHC -fno-float-in #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# OPTIONS_GHC -fno-warn-unused-binds #-}--#ifndef MIN_VERSION_base-#define MIN_VERSION_base(x,y,z) 1-#endif+{-# OPTIONS_GHC -Wno-orphans #-}+{-# OPTIONS_GHC -Wno-unused-binds #-}  ---------------------------------------------------------------------------- -- |@@ -77,10 +65,8 @@     -- * Reflection       Reifies(..)     , reify-#if __GLASGOW_HASKELL__ >= 708     , reifyNat     , reifySymbol-#endif     , reifyTypeable     -- * Given     , Given(..)@@ -108,31 +94,26 @@     ) where  import Control.Applicative+import Control.Exception  #ifdef MIN_VERSION_template_haskell import Control.Monad #endif  import Data.Bits--#if __GLASGOW_HASKELL__ < 710-import Data.Foldable-#endif--import Data.Semigroup as Sem+import Data.Coerce (Coercible, coerce) import Data.Proxy--#if __GLASGOW_HASKELL__ < 710-import Data.Traversable-#endif-+import Data.Semigroup as Sem import Data.Typeable import Data.Word import Foreign.Ptr import Foreign.StablePtr -#if (__GLASGOW_HASKELL__ >= 707) || (defined(MIN_VERSION_template_haskell) && USE_TYPE_LITS) import GHC.TypeLits+#if MIN_VERSION_base(4,10,0)+import qualified Numeric.Natural as Numeric (Natural)+#else+import Control.Exception (ArithException(..), throw) #endif  #ifdef __HUGS__@@ -149,10 +130,21 @@ import Unsafe.Coerce #endif -#ifdef HLINT-{-# ANN module "HLint: ignore Avoid lambda" #-}+#if MIN_VERSION_base(4,18,0)+import qualified GHC.TypeNats as TN #endif +-- Due to https://gitlab.haskell.org/ghc/ghc/issues/16893, inlining+-- unsafeCoerce too aggressively can cause optimization to become unsound on+-- old versions of GHC. As a workaround, we mark unsafeCoerce-using definitions+-- as NOINLINE where necessary.+-- See https://github.com/ekmett/reflection/issues/47.+#if __GLASGOW_HASKELL__ >= 811+# define INLINE_UNSAFE_COERCE INLINE+#else+# define INLINE_UNSAFE_COERCE NOINLINE+#endif+ ------------------------------------------------------------------------------ -- Reifies ------------------------------------------------------------------------------@@ -167,28 +159,27 @@ -- | Reify a value at the type level, to be recovered with 'reflect'. reify :: forall a r. a -> (forall (s :: *). Reifies s a => Proxy s -> r) -> r reify a k = unsafeCoerce (Magic k :: Magic a r) (const a) Proxy-{-# INLINE reify #-}+{-# INLINE_UNSAFE_COERCE reify #-} -#if __GLASGOW_HASKELL__ >= 707 instance KnownNat n => Reifies n Integer where   reflect = natVal  instance KnownSymbol n => Reifies n String where   reflect = symbolVal-#endif -#if __GLASGOW_HASKELL__ >= 708- -------------------------------------------------------------------------------- -- KnownNat -------------------------------------------------------------------------------- -newtype MagicNat r = MagicNat (forall (n :: Nat). KnownNat n => Proxy n -> r)- -- | This upgraded version of 'reify' can be used to generate a 'KnownNat' suitable for use with other APIs. --+-- Attemping to pass a negative 'Integer' as an argument will result in an+-- 'Underflow' exception.+-- -- /Available only on GHC 7.8+/ --+-- >>> import GHC.TypeLits+-- -- >>> reifyNat 4 natVal -- 4 --@@ -196,28 +187,59 @@ -- 4  reifyNat :: forall r. Integer -> (forall (n :: Nat). KnownNat n => Proxy n -> r) -> r-reifyNat n k = unsafeCoerce (MagicNat k :: MagicNat r) n Proxy+#if MIN_VERSION_base(4,18,0)+-- With base-4.18 or later, we can use the API in GHC.TypeNats to define this+-- function directly.+reifyNat n k = TN.withSomeSNat (fromInteger n :: Numeric.Natural) $+               \(sn :: (SNat n)) -> TN.withKnownNat sn $ k (Proxy :: Proxy n)+{-# INLINE reifyNat #-}+#else+-- On older versions of base, we resort to unsafeCoerce.+reifyNat n k = unsafeCoerce (MagicNat k :: MagicNat r)+# if MIN_VERSION_base(4,10,0)+                             -- Starting with base-4.10, the internal+                             -- representation of KnownNat changed from Integer+                             -- to Natural, so make sure to perform the same+                             -- conversion before unsafeCoercing.+                             (fromInteger n :: Numeric.Natural)+# else+                             (if n < 0 then throw Underflow else n)+# endif+                             Proxy+{-# INLINE_UNSAFE_COERCE reifyNat #-} +newtype MagicNat r = MagicNat (forall (n :: Nat). KnownNat n => Proxy n -> r)+#endif+ -------------------------------------------------------------------------------- -- KnownSymbol -------------------------------------------------------------------------------- -newtype MagicSymbol r = MagicSymbol (forall (n :: Symbol). KnownSymbol n => Proxy n -> r)- -- | This upgraded version of 'reify' can be used to generate a 'KnownSymbol' suitable for use with other APIs. -- -- /Available only on GHC 7.8+/ --+-- >>> import GHC.TypeLits+-- -- >>> reifySymbol "hello" symbolVal -- "hello" -- -- >>> reifySymbol "hello" reflect -- "hello" reifySymbol :: forall r. String -> (forall (n :: Symbol). KnownSymbol n => Proxy n -> r) -> r+#if MIN_VERSION_base(4,18,0)+-- With base-4.18 or later, we can use the API in GHC.TypeNats to define this+-- function directly.+reifySymbol s k = withSomeSSymbol s $ \(ss :: SSymbol s) -> withKnownSymbol ss (k (Proxy :: Proxy s))+{-# INLINE reifySymbol #-}+#else+-- On older versions of base, we resort to unsafeCoerce. reifySymbol n k = unsafeCoerce (MagicSymbol k :: MagicSymbol r) n Proxy-+{-# INLINE_UNSAFE_COERCE reifySymbol #-} #endif +newtype MagicSymbol r = MagicSymbol (forall (n :: Symbol). KnownSymbol n => Proxy n -> r)+ ------------------------------------------------------------------------------ -- Given ------------------------------------------------------------------------------@@ -238,7 +260,7 @@ -- are in scope, then the behavior is implementation defined. give :: forall a r. a -> (Given a => r) -> r give a k = unsafeCoerce (Gift k :: Gift a r) a-{-# INLINE give #-}+{-# INLINE_UNSAFE_COERCE give #-}  -------------------------------------------------------------------------------- -- Explicit Numeric Reflection@@ -288,9 +310,7 @@ -- in the \"Functional Pearl: Implicit Configurations\" paper by Oleg Kiselyov and Chung-Chieh Shan. -- -- @instance Num (Q Exp)@ provided in this package allows writing @$(3)@--- instead of @$(int 3)@. Sometimes the two will produce the same--- representation (if compiled without the @-DUSE_TYPE_LITS@ preprocessor--- directive).+-- instead of @$(int 3)@. int :: Int -> TypeQ int n = case quotRem n 2 of   (0, 0) -> conT ''Z@@ -307,12 +327,6 @@   | n >= 0 = int n   | otherwise = error "nat: negative" -#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ < 704-instance Show (Q a) where-  show _ = "Q"-instance Eq (Q a) where-  _ == _ = False-#endif instance Num a => Num (Q a) where   (+) = liftM2 (+)   (*) = liftM2 (*)@@ -329,29 +343,13 @@  -- | This permits the use of $(5) as a type splice. instance Num Type where-#ifdef USE_TYPE_LITS   LitT (NumTyLit a) + LitT (NumTyLit b) = LitT (NumTyLit (a+b))   a + b = AppT (AppT (VarT ''(+)) a) b    LitT (NumTyLit a) * LitT (NumTyLit b) = LitT (NumTyLit (a*b))   (*) a b = AppT (AppT (VarT ''(GHC.TypeLits.*)) a) b-#if MIN_VERSION_base(4,8,0)   a - b = AppT (AppT (VarT ''(-)) a) b-#else-  (-) = error "Type.(-): undefined"-#endif   fromInteger = LitT . NumTyLit-#else-  (+) = error "Type.(+): undefined"-  (*) = error "Type.(*): undefined"-  (-) = error "Type.(-): undefined"-  fromInteger n = case quotRem n 2 of-      (0, 0) -> ConT ''Z-      (q,-1) -> ConT ''PD `AppT` fromInteger q-      (q, 0) -> ConT ''D  `AppT` fromInteger q-      (q, 1) -> ConT ''SD `AppT` fromInteger q-      _ -> error "ghc is bad at math"-#endif   abs = error "Type.abs"   signum = error "Type.signum" @@ -386,27 +384,12 @@   signum = onProxyType1 signum   fromInteger n = ConE 'Proxy `SigE` (ConT ''Proxy `AppT` fromInteger n) -#ifdef USE_TYPE_LITS addProxy :: Proxy a -> Proxy b -> Proxy (a + b) addProxy _ _ = Proxy mulProxy :: Proxy a -> Proxy b -> Proxy (a * b) mulProxy _ _ = Proxy-#if MIN_VERSION_base(4,8,0) subProxy :: Proxy a -> Proxy b -> Proxy (a - b) subProxy _ _ = Proxy-#else-subProxy :: Proxy a -> Proxy b -> Proxy c-subProxy _ _ = error "Exp.(-): undefined"-#endif---  fromInteger = LitT . NumTyLit-#else-addProxy :: Proxy a -> Proxy b -> Proxy c-addProxy _ _ = error "Exp.(+): undefined"-mulProxy :: Proxy a -> Proxy b -> Proxy c-mulProxy _ _ = error "Exp.(*): undefined"-subProxy :: Proxy a -> Proxy b -> Proxy c-subProxy _ _ = error "Exp.(-): undefined"-#endif  #endif @@ -448,7 +431,7 @@   GO(T253,253) GO(T254,254) GO(T255,255)  #define GO(Tn,n) \-  newtype Tn = Tn Tn deriving Typeable; \+  newtype Tn = Tn Tn; \   instance B Tn where { \     reflectByte _ = n \   };@@ -466,9 +449,16 @@ _ -> impossible } -newtype W (b0 :: *) (b1 :: *) (b2 :: *) (b3 :: *) = W (W b0 b1 b2 b3) deriving Typeable-newtype Stable (w0 :: *) (w1 :: *) (a :: *) = Stable (Stable w0 w1 a) deriving Typeable+newtype W (b0 :: *) (b1 :: *) (b2 :: *) (b3 :: *) = W (W b0 b1 b2 b3)+newtype StableBox (w0 :: *) (w1 :: *) (a :: *) = StableBox (StableBox w0 w1 a)+newtype Stable (w0 :: *) (w1 :: *) (a :: *) = Stable (Stable w0 w1 a) +data Box a = Box a++stableBox :: p (Stable w1 w2 a) -> Proxy (StableBox w1 w2 a)+stableBox _ = Proxy+{-# INLINE stableBox #-}+ stable :: p b0 -> p b1 -> p b2 -> p b3 -> p b4 -> p b5 -> p b6 -> p b7        -> Proxy (Stable (W b0 b1 b2 b3) (W b4 b5 b6 b7) a) stable _ _ _ _ _ _ _ _ = Proxy@@ -482,35 +472,35 @@ intPtrToStablePtr = castPtrToStablePtr . intPtrToPtr {-# INLINE intPtrToStablePtr #-} -byte0 :: p (Stable (W b0 b1 b2 b3) w1 a) -> Proxy b0+byte0 :: p (StableBox (W b0 b1 b2 b3) w1 a) -> Proxy b0 byte0 _ = Proxy -byte1 :: p (Stable (W b0 b1 b2 b3) w1 a) -> Proxy b1+byte1 :: p (StableBox (W b0 b1 b2 b3) w1 a) -> Proxy b1 byte1 _ = Proxy -byte2 :: p (Stable (W b0 b1 b2 b3) w1 a) -> Proxy b2+byte2 :: p (StableBox (W b0 b1 b2 b3) w1 a) -> Proxy b2 byte2 _ = Proxy -byte3 :: p (Stable (W b0 b1 b2 b3) w1 a) -> Proxy b3+byte3 :: p (StableBox (W b0 b1 b2 b3) w1 a) -> Proxy b3 byte3 _ = Proxy -byte4 :: p (Stable w0 (W b4 b5 b6 b7) a) -> Proxy b4+byte4 :: p (StableBox w0 (W b4 b5 b6 b7) a) -> Proxy b4 byte4 _ = Proxy -byte5 :: p (Stable w0 (W b4 b5 b6 b7) a) -> Proxy b5+byte5 :: p (StableBox w0 (W b4 b5 b6 b7) a) -> Proxy b5 byte5 _ = Proxy -byte6 :: p (Stable w0 (W b4 b5 b6 b7) a) -> Proxy b6+byte6 :: p (StableBox w0 (W b4 b5 b6 b7) a) -> Proxy b6 byte6 _ = Proxy -byte7 :: p (Stable w0 (W b4 b5 b6 b7) a) -> Proxy b7+byte7 :: p (StableBox w0 (W b4 b5 b6 b7) a) -> Proxy b7 byte7 _ = Proxy  argument :: (p s -> r) -> Proxy s argument _ = Proxy  instance (B b0, B b1, B b2, B b3, B b4, B b5, B b6, B b7, w0 ~ W b0 b1 b2 b3, w1 ~ W b4 b5 b6 b7)-    => Reifies (Stable w0 w1 a) a where+    => Reifies (StableBox w0 w1 a) (Box a) where   reflect = r where       r = unsafePerformIO $ const <$> deRefStablePtr p <* freeStablePtr p       s = argument r@@ -525,22 +515,30 @@         (reflectByte (byte7 s) `shiftL` 56)   {-# NOINLINE reflect #-} --- This had to be moved to the top level, due to an apparent bug in--- the ghc inliner introduced in ghc 7.0.x-reflectBefore :: forall (proxy :: * -> *) s b. (Proxy s -> b) -> proxy s -> b-reflectBefore f = const $! f Proxy-{-# NOINLINE reflectBefore #-}+instance Reifies (StableBox w0 w1 a) (Box b) => Reifies (Stable w0 w1 a) b where+  reflect p = case reflect (stableBox p) of+    Box a -> a +-- Ensure that exactly one dictionary of Reifies (StableBox ...) is created and evaluated per reifyTypeable call.+--+-- Evaluating the dictionary's thunk frees the allocated StablePtr, and the contents of the StablePtr replace the thunk.+-- Creating two dictionaries would mean a double free upon their evaluation, and leaving a dictionary unevaluated would+-- leak the StablePtr (see https://github.com/ekmett/reflection/issues/54).+--+-- To separate evaluation of the dictionary and evaluation of the actual argument passed to reifyTypeable, we insert a+-- Box in between.+withStableBox :: Reifies (StableBox w0 w1 a) (Box a) => (Reifies (Stable w0 w1 a) a => Proxy (Stable w0 w1 a) -> r) -> Proxy (Stable w0 w1 a) -> IO r+withStableBox k p = do+  _ <- evaluate $ reflect (stableBox p)+  evaluate $ k p+{-# NOINLINE withStableBox #-}+ -- | Reify a value at the type level in a 'Typeable'-compatible fashion, to be recovered with 'reflect'. -- -- This can be necessary to work around the changes to @Data.Typeable@ in GHC HEAD. reifyTypeable :: Typeable a => a -> (forall (s :: *). (Typeable s, Reifies s a) => Proxy s -> r) -> r-#if MIN_VERSION_base(4,4,0) reifyTypeable a k = unsafeDupablePerformIO $ do-#else-reifyTypeable a k = unsafePerformIO $ do-#endif-  p <- newStablePtr a+  p <- newStablePtr (Box a)   let n = stablePtrToIntPtr p   reifyByte (fromIntegral n) (\s0 ->     reifyByte (fromIntegral (n `shiftR` 8)) (\s1 ->@@ -550,9 +548,7 @@             reifyByte (fromIntegral (n `shiftR` 40)) (\s5 ->               reifyByte (fromIntegral (n `shiftR` 48)) (\s6 ->                 reifyByte (fromIntegral (n `shiftR` 56)) (\s7 ->-                  reflectBefore (fmap return k) $-                    stable s0 s1 s2 s3 s4 s5 s6 s7))))))))-+                  withStableBox k $ stable s0 s1 s2 s3 s4 s5 s6 s7))))))))  data ReifiedMonoid a = ReifiedMonoid { reifiedMappend :: a -> a -> a, reifiedMempty :: a } @@ -577,7 +573,7 @@ reifyMonoid f z m xs = reify (ReifiedMonoid f z) (unreflectedMonoid (m xs))  -- | Fold a value using its 'Foldable' instance using--- explicitly provided 'Monoid' operations. This is like 'fold'+-- explicitly provided 'Monoid' operations. This is like 'Data.Foldable.fold' -- where the 'Monoid' instance can be manually specified. -- -- @@@ -634,5 +630,5 @@ sequenceBy :: Traversable t => (forall x. x -> f x) -> (forall x y. f (x -> y) -> f x -> f y) -> t (f a) -> f (t a) sequenceBy pur app = reifyApplicative pur app (traverse ReflectedApplicative) -(#.) :: (b -> c) -> (a -> b) -> a -> c-(#.) _ = unsafeCoerce+(#.) :: Coercible c b => (b -> c) -> (a -> b) -> (a -> c)+(#.) _ = coerce (\x -> x :: b) :: forall a b. Coercible b a => a -> b
reflection.cabal view
@@ -1,5 +1,5 @@ name:           reflection-version:        2.1.4+version:        2.1.9 license:        BSD3 license-file:   LICENSE author:         Edward A. Kmett, Elliott Hird, Oleg Kiselyov and Chung-chieh Shan@@ -25,20 +25,28 @@   and Chung-chieh Shan (<http://okmij.org/ftp/Haskell/tr-15-04.pdf original paper>).   However, the API has been streamlined to improve performance.   .-  Austin Seipp's tutorial <https://www.schoolofhaskell.com/user/thoughtpolice/using-reflection Reflecting values to types and back> provides a summary of the+  There are a handful of tutorials on how to use this library:+  .+  * Austin Seipp's tutorial <https://www.schoolofhaskell.com/user/thoughtpolice/using-reflection Reflecting values to types and back> provides a summary of the   approach taken by this library, along with more motivating examples.-tested-with:   GHC == 7.0.4-             , GHC == 7.2.2-             , GHC == 7.4.2-             , GHC == 7.6.3-             , GHC == 7.8.4-             , GHC == 7.10.3-             , GHC == 8.0.2+  .+  * Arnaud Spiwack's tutorial <https://www.tweag.io/posts/2017-12-21-reflection-tutorial.html All about reflection> explains how to use this library.+tested-with:   GHC == 8.0.2              , GHC == 8.2.2-             , GHC == 8.4.3-             , GHC == 8.6.1+             , GHC == 8.4.4+             , GHC == 8.6.5+             , GHC == 8.8.4+             , GHC == 8.10.7+             , GHC == 9.0.2+             , GHC == 9.2.8+             , GHC == 9.4.8+             , GHC == 9.6.6+             , GHC == 9.8.4+             , GHC == 9.10.1+             , GHC == 9.12.1  extra-source-files:+  .hlint.yaml   examples/reflection-examples.cabal   examples/LICENSE   examples/*.hs@@ -46,7 +54,6 @@   README.markdown   slow/Data/Reflection.hs   fast/Data/Reflection.hs-  .travis.yml  flag slow   description:@@ -68,28 +75,18 @@  library   ghc-options: -Wall+  if impl(ghc >= 8.6)+    ghc-options: -Wno-star-is-type -  if impl(ghc >= 7.2)-    default-extensions: Trustworthy+  default-extensions: Trustworthy    build-depends:-    base >= 2 && < 5--  if impl(ghc < 7.8)-    build-depends:-      tagged >= 0.4.4 && < 1--  if !impl(ghc >= 8.0)-    build-depends:-      semigroups >= 0.11 && < 0.19+    base >= 4.9 && < 5    default-language: Haskell98    if flag(template-haskell) && impl(ghc)-    if !impl(ghc >= 8.0)-      other-extensions: TemplateHaskell-    -- else-    --   other-extensions: TemplateHaskellQuotes -- Hackage doesn't know this extension yet+    -- other-extensions: TemplateHaskellQuotes -- Hackage doesn't know this extension yet     build-depends: template-haskell    if !flag(slow) && (impl(ghc) || impl(hugs))@@ -105,3 +102,19 @@     CPP    exposed-modules: Data.Reflection++test-suite spec+  type: exitcode-stdio-1.0+  hs-source-dirs: tests+  main-is: Spec.hs+  other-modules: ReifyNatSpec+                 T47Spec+  ghc-options: -Wall+  default-language: Haskell98+  build-tool-depends: hspec-discover:hspec-discover >= 1.8+  build-depends:+    base       >= 4.9 && < 5,+    containers >= 0.1 && < 0.8,+    hspec      >= 2   && < 3,+    QuickCheck >= 2   && < 3,+    reflection
slow/Data/Reflection.hs view
@@ -1,12 +1,15 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE MonoLocalBinds #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE Rank2Types #-}+{-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fno-cse #-} {-# OPTIONS_GHC -fno-full-laziness #-} {-# OPTIONS_GHC -fno-float-in #-}-{-# OPTIONS_GHC -fno-warn-unused-binds #-}+{-# OPTIONS_GHC -Wno-unused-binds #-} ---------------------------------------------------------------------------- -- | -- Module     : Data.Reflection@@ -49,6 +52,7 @@ import Foreign.StablePtr import System.IO.Unsafe import Control.Applicative+import Control.Exception import Data.Proxy import Data.Bits import Data.Word@@ -115,9 +119,18 @@   -- reified type.   reflect :: proxy s -> a +newtype StableBox b0 b1 b2 b3 b4 b5 b6 b7 a =+  StableBox (StableBox b0 b1 b2 b3 b4 b5 b6 b7 a) newtype Stable b0 b1 b2 b3 b4 b5 b6 b7 a =   Stable (Stable b0 b1 b2 b3 b4 b5 b6 b7 a) +data Box a = Box a++stableBox :: p (Stable b0 b1 b2 b3 b4 b5 b6 b7 a)+          -> Proxy (StableBox b0 b1 b2 b3 b4 b5 b6 b7 a)+stableBox _ = Proxy+{-# INLINE stableBox #-}+ stable :: p b0 -> p b1 -> p b2 -> p b3 -> p b4 -> p b5 -> p b6 -> p b7        -> Proxy (Stable b0 b1 b2 b3 b4 b5 b6 b7 a) stable _ _ _ _ _ _ _ _ = Proxy@@ -131,35 +144,35 @@ intPtrToStablePtr = castPtrToStablePtr . intPtrToPtr {-# INLINE intPtrToStablePtr #-} -byte0 :: p (Stable b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b0+byte0 :: p (StableBox b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b0 byte0 _ = Proxy -byte1 :: p (Stable b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b1+byte1 :: p (StableBox b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b1 byte1 _ = Proxy -byte2 :: p (Stable b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b2+byte2 :: p (StableBox b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b2 byte2 _ = Proxy -byte3 :: p (Stable b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b3+byte3 :: p (StableBox b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b3 byte3 _ = Proxy -byte4 :: p (Stable b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b4+byte4 :: p (StableBox b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b4 byte4 _ = Proxy -byte5 :: p (Stable b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b5+byte5 :: p (StableBox b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b5 byte5 _ = Proxy -byte6 :: p (Stable b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b6+byte6 :: p (StableBox b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b6 byte6 _ = Proxy -byte7 :: p (Stable b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b7+byte7 :: p (StableBox b0 b1 b2 b3 b4 b5 b6 b7 a) -> Proxy b7 byte7 _ = Proxy  argument :: (p s -> r) -> Proxy s argument _ = Proxy  instance (B b0, B b1, B b2, B b3, B b4, B b5, B b6, B b7)-    => Reifies (Stable b0 b1 b2 b3 b4 b5 b6 b7 a) a where+    => Reifies (StableBox b0 b1 b2 b3 b4 b5 b6 b7 a) (Box a) where   reflect = r where       r = unsafePerformIO $ const <$> deRefStablePtr p <* freeStablePtr p       s = argument r@@ -174,12 +187,34 @@         (reflectByte (byte7 s) `shiftL` 56)   {-# NOINLINE reflect #-} --- This had to be moved to the top level, due to an apparent bug in--- the ghc inliner introduced in ghc 7.0.x-reflectBefore :: Reifies s a => (Proxy s -> b) -> proxy s -> b-reflectBefore f = const $! f Proxy-{-# NOINLINE reflectBefore #-}+instance Reifies (StableBox b0 b1 b2 b3 b4 b5 b6 b7 a) (Box b)+    => Reifies (Stable b0 b1 b2 b3 b4 b5 b6 b7 a) b where+  reflect p = case reflect (stableBox p) of+    Box a -> a +-- Ensure that exactly one dictionary of Reifies (StableBox ...) is created and+-- evaluated per reifyTypeable call.+--+-- Evaluating the dictionary's thunk frees the allocated StablePtr, and the+-- contents of the StablePtr replace the thunk. Creating two dictionaries would+-- mean a double free upon their evaluation, and leaving a dictionary+-- unevaluated would leak the StablePtr+-- (see https://github.com/ekmett/reflection/issues/54).+--+-- To separate evaluation of the dictionary and evaluation of the actual+-- argument passed to reifyTypeable, we insert a Box in between.+withStableBox+  :: Reifies (StableBox b0 b1 b2 b3 b4 b5 b6 b7 a) (Box a)+  => (Reifies (Stable b0 b1 b2 b3 b4 b5 b6 b7 a) a+    => Proxy (Stable b0 b1 b2 b3 b4 b5 b6 b7 a)+    -> r)+  -> Proxy (Stable b0 b1 b2 b3 b4 b5 b6 b7 a)+  -> IO r+withStableBox k p = do+  _ <- evaluate $ reflect (stableBox p)+  evaluate $ k p+{-# NOINLINE withStableBox #-}+ -- | Reify a value at the type level, to be recovered with 'reflect'. reify :: a -> (forall s. (Reifies s a) => Proxy s -> r) -> r reify a k = unsafeDupablePerformIO $ do@@ -193,5 +228,4 @@             reifyByte (fromIntegral (n `shiftR` 40)) (\s5 ->               reifyByte (fromIntegral (n `shiftR` 48)) (\s6 ->                 reifyByte (fromIntegral (n `shiftR` 56)) (\s7 ->-                  reflectBefore (fmap return k) $-                    stable s0 s1 s2 s3 s4 s5 s6 s7))))))))+                  withStableBox k $ stable s0 s1 s2 s3 s4 s5 s6 s7))))))))
+ tests/ReifyNatSpec.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ScopedTypeVariables #-}+module ReifyNatSpec where++import Data.Reflection+import Test.Hspec.QuickCheck+import Test.QuickCheck (NonNegative(..))++#if MIN_VERSION_base(4,10,0)+import GHC.TypeNats (natVal)+import Numeric.Natural (Natural)+#endif++#if __GLASGOW_HASKELL__ != 900+import Control.Exception (ArithException(..), evaluate)+import Test.QuickCheck (Negative(..))+#endif++import Test.Hspec++main :: IO ()+main = hspec spec++spec :: Spec+spec =+  describe "reifyNat" $ do+    prop "reify positive Integers and reflect them back" $+      \(NonNegative (i :: Integer)) -> reifyNat i $ \p -> reflect p `shouldBe` i+#if __GLASGOW_HASKELL__ != 900+    -- Inexplicably, this test fails on GHC 9.0 with hspec-2.8.4 or later.+    -- Moreover, I suspect that undefined behavior is involved in some way,+    -- as the output of hspec will occasionally be swallowed entirely. I have+    -- not been able to observe this phenomenon on any other version of GHC,+    -- so I will simply disable this test on 9.0.+    prop "should throw an Underflow exception on negative inputs" $+      \(Negative (i :: Integer)) ->+        reifyNat i (evaluate . reflect) `shouldThrow` (== Underflow)+#endif+#if MIN_VERSION_base(4,10,0)+    it "should reflect very large Naturals correctly" $ do -- #41+      let d42, d2_63, d2_64 :: Natural+          d42   = 42+          d2_63 = 2^(63 :: Natural)+          d2_64 = 2^(64 :: Natural)+      reifyNat (toInteger d42)       $ \p -> natVal p `shouldBe` d42+      reifyNat (toInteger (d2_63-1)) $ \p -> natVal p `shouldBe` d2_63-1+      reifyNat (toInteger d2_63)     $ \p -> natVal p `shouldBe` d2_63+      reifyNat (toInteger (d2_64-1)) $ \p -> natVal p `shouldBe` d2_64-1+      reifyNat (toInteger d2_64)     $ \p -> natVal p `shouldBe` d2_64+#endif
+ tests/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ tests/T47Spec.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-}+-- | A regression test for issue #47.+module T47Spec where++import qualified Data.Map as M+import Data.Map (Map)+import Data.Reflection+import Test.Hspec++main :: IO ()+main = hspec spec++spec :: Spec+spec =+  describe "Given" $ do+    it "should give Normal properly" $+      give Normal (toJSON (Foo Bar)) `shouldBe`+      Object (M.fromList [("Foo",String "Bar")])+    it "should give ViaShow properly" $+      give ViaShow (toJSON (Foo Bar)) `shouldBe`+      Object (M.fromList [("Foo",String "SHOWBAR")])++----------------------------------------------------------------------------+-- Types+----------------------------------------------------------------------------++data Foo = Foo Bar++instance Show Foo where+  show _ = "SHOWFOO"++data Bar = Bar | BarBar++instance Show Bar where+  show _ = "SHOWBAR"++----------------------------------------------------------------------------+-- ToJSON instances+----------------------------------------------------------------------------++instance Given Style => ToJSON Foo where+  toJSON (Foo x) = Object $ M.singleton "Foo" (toJSON x)++instance Given Style => ToJSON Bar where+  toJSON x = case given of+    Normal -> String $ case x of+                Bar    -> "Bar"+                BarBar -> "BarBar"+    ViaShow -> String $ show x++data Style = Normal | ViaShow++----------------------------------------------------------------------------+-- Minimized aeson+----------------------------------------------------------------------------++class ToJSON a where+  toJSON :: a -> Value++data Value+  = Object !(Map String Value)+  | String !String+  deriving (Eq, Show)