[Haskell-cafe] implicit parameters THANK YOU!
thjaeger at gmail.com
Tue Mar 22 06:54:55 EST 2005
On Mon, 21 Mar 2005 20:29:35 -0500 (Eastern Standard Time), S.
Alexander Jacobson <alex at alexjacobson.com> wrote:
> I just discovered implicit parameters. To everyone involved with
> making them, THANK YOU. They are blazingly useful/powerful for server
> handler style libraries where you want to make a veriety of local
> environment information available to the handlers without burdening
> the handlers with a big dictionary object to carry around. FANTASTIC.
I like to think of implicit parameters as a direct-style reader monad.
Therefore, they can be used interchangably with reader monads (or with
explicit passing of the parameter, for that matter). Which one you
choose is of course a matter of taste, but personally, I prefer the
monadic approach, since it is easier to extend (maybe you later
discover that you really needed state) and it is the usual (and
portable) Haskell solution. Furthermore, because `(->) r' already is a
reader monad, the code can often be kept very consice.
The situation is different if you've already written some code and
realize you need an additional parameter in a couple of functions.
Monadifying all that code (or explicitely threading the parameter) is
usually a lot of trouble and the change might be only experimental
anyway, so with implicit parameters, you can just change a few
signatures and be done.
> That being said, they so powerful they are proabably easy to abuse.
> Could those experienced with this feature provide warnings about
> possible problems with overuse?
I've only used them sparsely and I think that's the way to go. Also,
you should be aware of a few common problems:
1. Recursive functions
This is not surprising if you consider how type inference for
recursive functions works, but it is obviously the wrong thing to do.
Personally, I'd be happy if (mutually) recursive functions using
implicit parameters without a type signature were rejected, because to
do it correctly, some sort of polymorphic recursion is necessary.
2. The monomorphism restriction
> a :: Int
> a = let ?foo = 0 in b where
> b :: (?foo :: Int) => Int
> b = let ?foo = 1 in c where
> c = ?foo
The meaning of this code depends on the flag
-f(no)-monomorphism-restriction since with the monomorphism turned on,
`c' gets the monomorphic type `Int', and the `?foo' in the definition
of `c' refers to the implicit parameter of `b', so `a' evaluates to
`0'. On the other hand, without the monomorphism restriction, the type
of `c' becomes `(?foo :: Int) => Int', and it is easy to see that `a'
evaluates to `0'.
The fact that the meaning depends on the type signature actually isn't
that bad; after all, in explicit monadic code, you would have to make
the same choice. The interaction with the monomorphism restriction,
however, seems very unfortunate.
Btw, to explicitely type a declaration in a let binding, the style
"let x :: a = b" isn't enough, it needs to be "let x :: a; x = b".
More information about the Haskell-Cafe