summaryrefslogtreecommitdiff
path: root/testsuite/tests/perf/should_run/T10359.hs
diff options
context:
space:
mode:
Diffstat (limited to 'testsuite/tests/perf/should_run/T10359.hs')
-rw-r--r--testsuite/tests/perf/should_run/T10359.hs125
1 files changed, 0 insertions, 125 deletions
diff --git a/testsuite/tests/perf/should_run/T10359.hs b/testsuite/tests/perf/should_run/T10359.hs
deleted file mode 100644
index fa10560970..0000000000
--- a/testsuite/tests/perf/should_run/T10359.hs
+++ /dev/null
@@ -1,125 +0,0 @@
-{-# LANGUAGE RankNTypes #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ConstraintKinds #-}
-
-module Main( main, boo ) where
-
-import Prelude hiding (repeat)
-
-boo xs f = (\x -> f x, xs)
-
-repeat :: Int -> (a -> a) -> a -> a
-repeat 1 f x = f x
-repeat n f x = n `seq` x `seq` repeat (n-1) f $ f x
-
----- Buggy version
-------------------
-
-type Numerical a = (Fractional a, Real a)
-
-data Box a = Box
- { func :: forall dum. (Numerical dum) => dum -> a -> a
- , obj :: !a }
-
-do_step :: (Numerical num) => num -> Box a -> Box a
-do_step number Box{..} = Box{ obj = func number obj, .. }
-
-start :: Box Double
-start = Box { func = \x y -> realToFrac x + y
- , obj = 0 }
-
-test :: Int -> IO ()
-test steps = putStrLn $ show $ obj $ repeat steps (do_step 1) start
-
----- Driver
------------
-
-main :: IO ()
-main = test 2000 -- compare test2 10000000 or test3 10000000, but test4 20000
-
-
-{-
----- No tuple constraint synonym is better
-------------------------------------------
-
-data Box2 a = Box2
- { func2 :: forall num. (Fractional num, Real num) => num -> a -> a
- , obj2 :: !a }
-
-do_step2 :: (Fractional num, Real num) => num -> Box2 a -> Box2 a
-do_step2 number Box2{..} = Box2{ obj2 = func2 number obj2, ..}
-
-start2 :: Box2 Double
-start2 = Box2 { func2 = \x y -> realToFrac x + y
- , obj2 = 0 }
-
-test2 :: Int -> IO ()
-test2 steps = putStrLn $ show $ obj2 $ repeat steps (do_step2 1) start2
-
----- Not copying the function field works too
----------------------------------------------
-
-do_step3 :: (Numerical num) => num -> Box a -> Box a
-do_step3 number b@Box{..} = b{ obj = func number obj }
-
-test3 :: Int -> IO ()
-test3 steps = putStrLn $ show $ obj $ repeat steps (do_step3 1) start
-
----- But record wildcards are not at fault
-------------------------------------------
-
-do_step4 :: (Numerical num) => num -> Box a -> Box a
-do_step4 number Box{func = f, obj = x} = Box{ obj = f number x, func = f }
-
-test4 :: Int -> IO ()
-test4 steps = putStrLn $ show $ obj $ repeat steps (do_step4 1) start
--}
-
-
-{-
-First of all, very nice example. Thank you for making it so small and easy to work with.
-
-I can see what's happening. The key part is what happens here:
-{{{
-do_step4 :: (Numerical num) => num -> Box a -> Box a
-do_step4 number Box{ func = f, obj = x}
- = Box{ func = f, obj = f number x }
-}}}
-After elaboration (ie making dictionaries explicit) we get this:
-{{{
-do_step4 dn1 number (Box {func = f, obj = x })
- = Box { func = \dn2 -> f ( case dn2 of (f,r) -> f
- , case dn2 of (f,r) -> r)
- , obj = f dn1 number x }
-}}}
-That's odd! We expected this:
-{{{
-do_step4 dn1 number (Box {func = f, obj = x })
- = Box { func = f
- , obj = f dn1 number x }
-}}}
-And indeed, the allocation of all those `\dn2` closures is what is causing the problem.
-So we are missing this optimisation:
-{{{
- (case dn2 of (f,r) -> f, case dn2 of (f,r) -> r)
-===>
- dn2
-}}}
-If we did this, then the lambda would look like `\dn2 -> f dn2` which could eta-reduce to `f`.
-But there are at least three problems:
- * The tuple transformation above is hard to spot
- * The tuple transformation is not quite semantically right; if `dn2` was bottom, the LHS and RHS are different
- * The eta-reduction isn't quite semantically right: if `f` ws bottom, the LHS and RHS are different.
-
-You might argue that the latter two can be ignored because dictionary arguments are special;
-indeed we often toy with making them strict.
-
-But perhaps a better way to avoid the tuple-transformation issue would be not to construct that strange expression in the first place. Where is it coming from? It comes from the call to `f` (admittedly applied to no arguments) in `Box { ..., func = f }`. GHC needs a dictionary for `(Numerical dum)` (I changed the name of the type variable in `func`'s type in the definition of `Box`). Since it's just a pair GHC says "fine, I'll build a pair, out of `Fractional dum` and `Real dum`. How does it get those dictionaries? By selecting the components of the `Franctional dum` passed to `f`.
-
-If GHC said instead "I need `Numerical dum` and behold I have one in hand, it'd be much better. It doesn't because tuple constraints are treated specially. But if we adopted the idea in #10362, we would (automatically) get to re-use the `Numerical dum` constraint. That would leave us with eta reduction, which is easier.
-
-As to what will get you rolling, a good solution is `test3`, which saves instantiating and re-generalising `f`. The key thing is to update all the fields ''except'' the polymorphic `func` field. I'm surprised you say that it doesn't work. Can you give a (presumably more complicated) example to demonstrate? Maybe there's a separate bug!
-
--}
-
-