Folks

I agree with Sigbjorn about argv, rather strongly, though apparently nobody
else does.

The Glasgow Haskell Compiler used to deal with command-line arguments in the
way mandated by Haskell 1.3; that is, we did a getArgs at the beginning and
then passed the arguments everywhere.

I recently undid all that.  Instead I now go

        module CmdLineOpts where
        
        argv = unsafePerformIO getArgs

        unfoldSize :: Int
        unfoldSize = lookupInt "-funfold-size" argv

        useCleverFiniteMap :: Bool
        useCleverFiniteMap = lookup "-fclever" argv

        ...etc..

That is, all the flags are unswizzled and turned into global
constants.

It was Just Too Painful to pass the flags everywhere.  For example, deep in
some dark corner of the transformation system there's a constant that
says how big a function body can be before GHC inlines it.  Threading
the command-line arguments all the way to that site is desperately painful. 
It's even worse if you discover that you'd like a command-line-controllable
thing in a dark corner that doesn't yet have the plumbing... you have to add
an extra argument to a chain of functions all the way to the top.

Passing the flags around costs extra instructions (not many each time, but a
lot of times).  Furthermore, even the flag test is expensive.  You can't
pass 100 flags individually, so you pass a single value and do a lookup each
time you want to test the flag.  Contrast that with a global thunk that
gets updated to a boolean the first time you use it.


I would put up with this pain (programming inconvenience, execution time
cost) if it bought me anything.  For example, you could make some of the
same complaints about the IO monad (it has to be propagated down to where
you use it), but there is a payoff: the order of IO operations is precisely
specified.

But in the case of argv, THERE IS NO BENEFIT WHATSOEVER.  None.  Zero.  Nix.
Nil.  Null.  Not even a little bit.   Will Partain calls this sort of thing
"functional programmer's death wish".  

argv really is a constant for any particular run of the program (I'm
excluding the ability that C programmers have to modify argv; I'll take a
copy at the start of the run, and that's what you get as the constant).  No
program transformations are restricted if argv is a constant.  No reasoning
principles are lost.


Well that's my rant for today.  I havn't said this before because there's an
easy workaround using unsafePerformIO; but unsafePerformIO isn't standard
Haskell, and it's a bit unsatisfactory that GHC is therefore not standard
Haskell in a way that would be very hard to fix.  I'd certainly prefer it if
argv was a standard-Haskell constant.

Simon

PS. I'm less steamed up about the stdin issue; but I think you missed
Sigbjorn's point.  Yes stdin is a constant now, but he'd like stdin *not* to
be a constant, so that he could take a value of type IO () that used stdin,
and reconnect its stdin to (say) a file.






Reply via email to