[GHC] #7036: StableNames in presence of class constraints / monadic functions
GHC
cvs-ghc at haskell.org
Thu Jun 28 17:15:06 CEST 2012
#7036: StableNames in presence of class constraints / monadic functions
------------------------------+---------------------------------------------
Reporter: ifigueroap | Owner:
Type: feature request | Status: new
Priority: normal | Component: GHC API
Version: 7.4.2 | Keywords:
Os: Unknown/Multiple | Architecture: Unknown/Multiple
Failure: None/Unknown | Testcase:
Blockedby: | Blocking:
Related: |
------------------------------+---------------------------------------------
Hi,
I'm trying to implement a notion of function equality using the
StableNames API.
So far it has worked relatively well, but I'm facing the problem of
getting negatives when functions have class constraints, like (Monad m).
I implemented de eq function as follows:
{{{
import System.Mem.StableName
import Control.Monad.State
eq :: a -> b -> IO Bool
eq a b = do
pa <- makeStableName a
pb <- makeStableName b
return (hashStableName pa == hashStableName pb)
}}}
And for testing the following function and main program:
{{{
successor :: (Num a, Monad m) => a -> m a
successor n = return (n+1)
main :: IO ()
main = do
b1 <- eq (successor :: Int -> Maybe Int) (successor :: Int -> Maybe
Int)
b2 <- eq (successor :: Int -> State Int Int) (successor :: Int ->
State Int Int)
print (show b1 ++ " " ++ show b2)
}}}
Running the program in ghci, gives "False False". Somewhere on the
internet there is a tip to use a compiled module with optimizations, using
ghc --make -O File.hs. Doing this, I get "True True".
However, with a slight modification of main the result is "True False":
{{{
main :: IO ()
main = do
b2 <- eq (successor :: Int -> State Int Int) (successor :: Int ->
State Int Int)
b1 <- eq (successor :: Int -> Maybe Int) (successor :: Int -> Maybe
Int)
print (show b1 ++ " " ++ show b2)
}}}
After reading a lots of forums and mail lists, it seems the problem is
because of the dictionary-passing style: somehow StableNames see that the
dictionaries are different and then returns false [1]. Or maybe there are
some closures created in background, that do not map to the same memory
locations.
I know that doing a let/where binding, this particular example works,
e.g.:
{{{
main :: IO ()
main = do
b2 <- eq f2 f2
b1 <- eq f1 f1
print (show b1 ++ " " ++ show b2)
where f1 = (successor :: Int -> Maybe Int)
f2 = (successor :: Int -> State Int Int)
}}}
But in general it is cumbersome to do this way, and it is hard to
anticipate whether the comparison is going to be "ok" or not. Another way
I've found to solve the problem is to put very explicit type annotations,
but this is problematic in monadic code that is intended to be generic.
I wonder if it is possible to implement some compiler flag to change the
behavior of StableNames (or maybe a differente API?) so it returns true
when the only difference is the dictionary?
In Scheme/Racket this notion of function equality is done tagging every
function with a unique value, upon closure creation. Using the macro
system this is done transparently for the programmer. I guess I could
emulate this using a wrapper type for functions, and using GHC.Unique; but
I want to see if there are other options. Maybe a compiler plugin can
annotate functions in the same way? It seems with Template Haskell is not
possible to intercept function definition.
Also, the example works correctly (returning "True True" in both cases)
when the definition of eq is:
{{{
eq :: a -> b -> IO Bool
eq a b = do
unsafeCoerce b a
pa <- makeStableName a
pb <- makeStableName b
return (hashStableName pa == hashStableName pb)
}}}
I guess it is because the dictionaries are somehow unified. But using this
eq in general leads to (predictable) Bus errors.
Thanks!
[1] http://www.haskell.org/pipermail/glasgow-haskell-
users/2011-November/021272.html
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/7036>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the Glasgow-haskell-bugs
mailing list