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