GHC: Ticket Query
http://ghc.haskell.org/trac/ghc/query?status=!closed&reporter=NickSmallbone&order=priority
The Glasgow Haskell Compileren-USGHChttp://ghc.haskell.org/trac/ghc/chrome/site/ghc_logo.png
http://ghc.haskell.org/trac/ghc/query?status=!closed&reporter=NickSmallbone&order=priority
Trac 1.0.1
http://ghc.haskell.org/trac/ghc/ticket/3620
http://ghc.haskell.org/trac/ghc/ticket/3620#3620: The seeds generated by split are not independentWed, 28 Oct 2009 15:07:41 GMTNickSmallbone<p>
Suppose we split a seed into two like this:
</p>
<pre class="wiki">split' :: StdGen -> (StdGen, StdGen)
split' g = (g12, g21)
where (_, g12) = split g1
(g21, _) = split g2
(g1, g2) = split g
</pre><p>
Since g1 and g2 are independent, g12 and g21 ought to be too. But they're not! If we use both of g12 and g21 to generate a random number in the range [0..10], then the two numbers ought to be equal 1/11 of the time. In fact, they're never equal.
Here is a test program that ought to return True 1/11 of the time but
actually always returns False:
</p>
<pre class="wiki">sample :: StdGen -> (Int, Int)
sample g = (fst (randomR (0, 10) g1),
fst (randomR (0, 10) g2))
where (g1, g2) = split' g
test :: StdGen -> Bool
test g = fst (sample g) == snd (sample g)
</pre><p>
I attached a program that prints the distribution of values from
<tt>test</tt> for other ranges than [0..10]. The distribution is
always quite bad no matter what the range is.
</p>
<p>
The upshot of all this is that the following <a class="missing wiki">QuickCheck?</a> (version 2)
property always passes, even though it's false:
</p>
<pre class="wiki">import Test.QuickCheck
import Text.Show.Functions
newtype Eleven = Eleven Int deriving Eq
instance Arbitrary Eleven where
arbitrary = fmap Eleven (choose (0, 10))
prop :: (Int -> Eleven) -> Bool
prop f = f 5 /= f 6
</pre>Resultshttp://ghc.haskell.org/trac/ghc/ticket/3620#changelog
http://ghc.haskell.org/trac/ghc/ticket/5463
http://ghc.haskell.org/trac/ghc/ticket/5463#5463: SPECIALISE pragmas generated from Template Haskell are ignoredMon, 05 Sep 2011 18:56:10 GMTNickSmallbone<p>
Hi,
</p>
<p>
I have the following program which contains a SPECIALISE pragma:
</p>
<pre class="wiki">module Test(threeList) where
{-# NOINLINE three #-}
three :: Monad m => m Int
three = return 3
{-# SPECIALISE three :: [Int] #-}
threeList :: [Int]
threeList = three
</pre><p>
The specialisation works and -ddump-simpl gives me the following:
</p>
<pre class="wiki">a :: Int
[GblId, Caf=NoCafRefs, Str=DmdType m]
a = I# 3
threeList [InlPrag=NOINLINE] :: [Int]
[GblId, Caf=NoCafRefs, Str=DmdType]
threeList = : @ Int a ([] @ Int)
</pre><p>
Suppose now I alter my program so that it uses Template Haskell to generate the SPECIALISE pragma:
</p>
<pre class="wiki">{-# LANGUAGE TemplateHaskell #-}
module TestTH(threeList) where
import TH
{-# NOINLINE three #-}
three :: Monad m => m Int
three = return 3
$(specialise 'three)
threeList :: [Int]
threeList = three
{-# LANGUAGE TemplateHaskell #-}
module TH where
import Language.Haskell.TH
specialise :: Name -> DecsQ
specialise x = do
listInt <- [t| [Int] |]
return [ PragmaD (SpecialiseP x listInt Nothing) ]
</pre><p>
The specialisation should work just as before. However, if I compile with -ddump-splices -ddump-simpl, I see that the correct pragma was spliced in but no specialisation happened and GHC generated icky code:
</p>
<pre class="wiki">TestTH.hs:1:1: Splicing declarations
specialise 'three
======>
TestTH.hs:9:3-19
{-# SPECIALIZE three :: [Int] #-}
==================== Tidy Core ====================
lvl :: Int
[GblId, Caf=NoCafRefs, Str=DmdType m]
lvl = I# 3
three [InlPrag=NOINLINE] :: forall (m :: * -> *). Monad m => m Int
[GblId, Arity=1, Caf=NoCafRefs, Str=DmdType U(AASA)]
three =
\ (@ m::* -> *) ($dMonad :: Monad m) ->
return @ m $dMonad @ Int lvl
threeList :: [Int]
[GblId,
Str=DmdType,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
ConLike=False, Cheap=False, Expandable=True,
Guidance=IF_ARGS [] 2 0}]
threeList = three @ [] $fMonad[]
</pre><p>
This happens on at least GHC 7.0.4 and 7.2.1.
</p>
Resultshttp://ghc.haskell.org/trac/ghc/ticket/5463#changelog
http://ghc.haskell.org/trac/ghc/ticket/8589
http://ghc.haskell.org/trac/ghc/ticket/8589#8589: Bad choice of loop breaker with INLINABLE/INLINEMon, 02 Dec 2013 12:27:59 GMTNickSmallbone<p>
Take the following program, which defines a pair of lists recursively:
</p>
<pre class="wiki">module Test(xs, ys) where
pair :: ([Bool], [Bool])
pair = (False:xs, True:ys)
where
(xs, ys) = pair
(xs, ys) = pair
</pre><p>
GHC is clever enough to disentangle <tt>xs</tt> from <tt>ys</tt> and with <tt>-ddump-simpl -O</tt> I get:
</p>
<pre class="wiki">Rec {
xs [Occ=LoopBreaker] :: [Bool]
[GblId, Caf=NoCafRefs, Str=DmdType]
xs = : False xs
end Rec }
Rec {
ys [Occ=LoopBreaker] :: [Bool]
[GblId, Caf=NoCafRefs, Str=DmdType]
ys = : True ys
end Rec }
</pre><p>
However, if I mark <tt>pair</tt> as <tt>INLINABLE</tt> or <tt>INLINE</tt> (it doesn't matter which), I get much worse code where <tt>xs</tt> and <tt>ys</tt> go through <tt>pair</tt>:
</p>
<pre class="wiki">Rec {
pair [InlPrag=INLINABLE[ALWAYS], Occ=LoopBreaker]
:: ([Bool], [Bool])
[GblId,
Str=DmdType m,
Unf=Unf{Src=InlineStable, TopLvl=True, Arity=0, Value=True,
ConLike=True, WorkFree=False, Expandable=True,
Guidance=IF_ARGS [] 50 30
Tmpl= (: False
(case pair of _ { (xs1_Xf6 [Occ=Once], _) -> xs1_Xf6 }),
: True (case pair of _ { (_, ys1_Xf6 [Occ=Once]) -> ys1_Xf6 }))}]
pair = (a1_rgo, a_rgn)
ys_ys :: [Bool]
[GblId,
Str=DmdType,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
ConLike=False, WorkFree=True, Expandable=True,
Guidance=IF_ARGS [] 10 0}]
ys_ys = case pair of _ { (xs1_XeW, ys1_Xf7) -> ys1_Xf7 }
a_rgn :: [Bool]
[GblId, Str=DmdType]
a_rgn = : True ys_ys
xs_xs :: [Bool]
[GblId,
Str=DmdType,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
ConLike=False, WorkFree=True, Expandable=True,
Guidance=IF_ARGS [] 10 0}]
xs_xs = case pair of _ { (xs1_XeW, ys1_XeS) -> xs1_XeW }
a1_rgo :: [Bool]
[GblId, Str=DmdType]
a1_rgo = : False xs_xs
end Rec }
ys :: [Bool]
[GblId,
Str=DmdType,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
ConLike=False, WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(unsat_ok=True,boring_ok=True)}]
ys = ys_ys
xs :: [Bool]
[GblId,
Str=DmdType,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
ConLike=False, WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(unsat_ok=True,boring_ok=True)}]
xs = xs_xs
</pre><p>
It seems that GHC chooses <tt>pair</tt> as the loop breaker, which stops the simplifier in its tracks.
</p>
<p>
It might seem a bit silly to mark <tt>pair</tt> as <tt>INLINE</tt>, since it's not mutually recursive. The function I really had was polymorphic with a typeclass constraint, and I wrote <tt>INLINABLE</tt> to get it specialised at its call site. (Also, <tt>pair</tt> is mutually recursive in the Core, so you would expect GHC to avoid using it as a loop breaker if I mark it <tt>INLINE</tt>.)
</p>
Resultshttp://ghc.haskell.org/trac/ghc/ticket/8589#changelog