[Haskell] Re: Using implicit parameter constraints in data decl

Ben Rudiak-Gould Benjamin.Rudiak-Gould at cl.cam.ac.uk
Mon Nov 8 20:18:16 EST 2004

Benjamin Franksen wrote:

 >Functions with implicit parameters *are* first class values but only 
if you
 >use -fglasgow-exts and not only -fimplicit-params.

Careful, they're still not entirely first class. For example, you can't 
pass types with implicit parameters as arguments to type constructors, 
so "IO ((?val::Bool) => String)" will still be rejected, even with 

(While experimenting with this, I discovered to my surprise that GHCi 
accepts the type "IO ((Num a) => a)", and describes it as "forall a. IO 
({Num a} => a)". However it rejects "return 12 :: IO ((Num a) => a)", 
saying that it can't deduce (Num ({Num a} => a)). Is this a bug?)

 >The version above is
 >rejected nonetheless (for whatever reason I can't figure out at the 

There's actually a good reason for this. The three declarations

    data (?val::Bool) => Test = Test { name :: String }
    data Test = (?val::Bool) => Test { name :: String }
    data Test = Test { name :: (?val::Bool) => String }

all mean different things.

The first one makes (?val::Bool) a constraint on the type constructor 
Test, meaning that any type that mentions Test will be required to have 
a (?val::Bool) context also. This is basically useless in practice, 
since it just adds a dummy function parameter which is (in general) 
never actually used. Type-class constraints in this position are 
deprecated, and I guess implicit-parameter constraints were never 
allowed in the first place.

The second declaration makes (?val::Bool) a constraint on the *data* 
constructor Test, so the data constructor gets the type (?val::Bool) => 
String -> Test. The constructor stores the value of ?val in a second 
quasi-hidden field in the constructed value. When it's later 
deconstructed by pattern matching, the value becomes "available" again, 
even though it doesn't appear explicitly in the pattern. This has a 
clear semantics for type-class constraints because they are always 
attached to particular explicit values, but I don't know how much sense 
it makes for implicit parameters.

The third declaration makes (?val::Bool) a constraint on a particular 
*field* of the data constructor, so Test has the type ((?val::Bool) => 
String) -> Test. This simply constrains the type of that field. There 
are no extra hidden fields.

-- Ben

More information about the Haskell mailing list