wiki:SafeRoles/Pre78GND

GND Pre-GHC-7.8

We will ignore the type-safety issues as they have been resolved, instead we'll just look at the module boundary / abstraction issues.

In GHC 7.6 or earlier, assume a library author writes the following MinList data type:

module MinList (
        MinList, newMinList, insertMinList,
    ) where

data MinList a = MinList a [a] deriving (Show)

newMinList :: Ord a => a -> MinList a
newMinList n = MinList n []

insertMinList :: Ord a => MinList a -> a -> MinList a
insertMinList s@(MinList m xs) n | n > m     = MinList m (n:xs)
                                 | otherwise = s

The MinList data type has an invariant (that depends on the Ord typeclass for the type parameter a that MinList is instantiated at) that after initialization it doesn't accept any element less than the initial element.

In GHC 7.6 and earlier, we could use GND to violate this invariant:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Main where

import MinList

class IntIso t where
    intIso :: c t -> c Int

instance IntIso Int where
    intIso = id

newtype Down a = Down a deriving (Eq, IntIso)

instance Ord a => Ord (Down a) where
    compare (Down a) (Down b) = compare b a

fine :: MinList (Down Int)
fine = foldl (\x y -> insertMinList x $ Down y) (newMinList $ Down 0) [-1,-2,-3,-4,1,2,3,4]

unsafeCast :: MinList (Down Int) -> MinList Int
unsafeCast = intIso

bad :: MinList Int
bad = unsafeCast fine

main = do
    print bad

Essentially, through GND we have created the function unsafeCast :: MinList (Down Int) -> MinList Int. This is a function we can't write by hand since we don't have access to the MinList constructor and so can't "see" into the data type.

Safe Haskell Pre-GHC-7.8

Due to both the type-safety and abstraction issues, GND was considered unsafe in Safe Haskell.

Last modified 3 years ago Last modified on Apr 30, 2015 6:02:47 PM