[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