[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
-fglasgow-exts.
(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
moment)
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