5

I'm messing around with the SPECIALIZE pragma while trying to find a solution to this problem.

I came up with this example:

{-# LANGUAGE FlexibleContexts, GeneralizedNewtypeDeriving #-}

import Data.Vector
import qualified Data.Vector.Generic as V

class Foo a

newtype Phantom m = T Int deriving (Show)

instance (Foo m) => Num (Phantom m)

f :: (Num r, V.Vector v r) => v r -> v r -> v r
{-# SPECIALIZE f :: (Foo m) => Vector (Phantom m) -> Vector (Phantom m) -> Vector (Phantom m) #-}
f x y = V.zipWith (+) x y

main = print "hello"

which fails to compile (GHC 7.6.2) because

Forall'd constraint `Foo m' is not bound in RULE lhs.

Googling only turned up a couple of GHC bug reports from years ago. I didn't see anything about "forall'd constraints" while reading about SPECIALIZE or RULE. My specialize signature does seem less polymorphic than the original, and it satisfies the "if-and-only-if" rule.

Community
  • 1
  • 1
crockeea
  • 21,651
  • 10
  • 48
  • 101

1 Answers1

3

replace with

{-# SPECIALIZE f :: (Num (Phantom m)) => Vector (Phantom m) -> Vector (Phantom m) -> Vector (Phantom m) #-}

and it will work. The r in Num r is Phantom m not m, thus you can't add the constraint Num m. This is logical--Num (Phantom m) does not imply Num m and you could get other instances under the open world assumption.

EDIT: You actually don't need any constraint at all in this case

{-# SPECIALIZE f :: Vector (Phantom m) -> Vector (Phantom m) -> Vector (Phantom m) #-}

anyway, the basic problem if I understand what you are trying to do is that you can't constrain when you perform an optimization based on phantom type parameters.

Philip JF
  • 28,199
  • 5
  • 70
  • 77
  • I'm automatically deriving `Num` for `Phantom m`, and the derived instance shouldn't need any constraints, as the newtype is a synonym for Int. I was really trying to restrict the little-p phantom type. Perhaps `Num` was a poor choice for my constraint on `m`. Make it `Foo m` for any type `Foo :: * -> *` – crockeea Nov 07 '13 at 07:02
  • Clearly I simplified the problem too much. I updated the problem again so that the `Foo m` constraint is needed as part of `Phantom m`'s `Num` instance. So what I'd *like* to constrain is the phantom type itself. I see that I can accomplish minimal specialization using the `Num (Phantom m)` constraint as you suggested, but is there a way to specialize further for more specific classes of m? Maybe `Bar` inherits from `Foo`, and I'd like to specialize for `Bar m`. At any rate, I'm really interested in what this error means. – crockeea Nov 07 '13 at 14:49