I need some help

Jorge Adriano jadrian@mat.uc.pt
Tue, 26 Mar 2002 15:46:13 +0000


[Obs: moving to haskell cafe]
[beware, huge answer follows]

> Hello
>   I am writing a whole program which is analyz a elegtromagnetic wave. This
> is ok but in the program I use a lot of constant for example pi,epsilon
> etc. I want to ask that
>   how I use a constant in Haskell ?

Defining constants it's easy, examples.
-- with no type signature
epsilon = 3.1

-- with explicit type signature
epsilon2 :: Double
epsilon2 = 3.1
 
-- specifying the type but no type signature
epsilon3 = 3.1 :: Double
 
(by the way, wouldn't it make sense not to get a warning about missing type 
signature in this last case. I know there is no signature there but still...)


> However the user of the program give some argument then program is
> starting. And I want to use this arguments for example at the end of the
> program. What will I do.
Good question. I've had a bad time with this, some in this list proably got 
tired of me saying the same thing over and over again... those of you might 
want to skip the rest of my mail :-)

If you want the user to be able to chose those values, then they are NOT 
constants, period. Yes their values won't chnage during the rest of the 
algorithm, but that doesn't makes it constants, so you can't declare them 
that way.

What *can* you do.
1. One *awfull* option is to pass thos values as arguments to all your 
functions. Yes signatures will get monstruous, it will complicate the 
developing process etc,

2. Instead of passing all those variables, group them in a record - data type 
with named fields - and pass that record arround.
(http://www.haskell.org/onlinereport/exps.html#sect3.15)
Signatures will get better. It's kind of weird though, to always have to pass 
around that record. Things can get quite messy, IMO.
-- foo
f :: Double -> Double -> Double
f x y = eta*x - epsilon^2*y

-- foo2
f :: Options -> Double -> Double -> Double
f opt x y = (eta opt)* (epsilon opt)^2*y

And this is just a very simple example, it can get much worst. 

3. Implicit parameters. (At least in Ghc, what about others?)
Now this is the closest to an elegant solution. 
*Read both*: 
http://citeseer.nj.nec.com/246042.html
http://www.cs.chalmers.se/~rjmh/Globals.ps


f :: (?eta::Double, ?epsilon::Double)=> Double -> Double -> Double
f x y = ?eta*x - ?epsilon^2*y

Now you don't have to specify eta and epsilon in the type signature itself, 
but in the context - no passing around extra (not natural) parameters. It 
makes an huge diference IMO when developing your algorithms. 


Still signatures wil get even bigger than if you just passed them as 
parameters, you can't even type the context like: (?eta, ?epsilon::Double)
So that is just awfull!

Once again records will help.
f :: (?opt::Options)=> Double -> Double -> Double
f x y = (eta ?opt) *x - (epsilon ?opt)^2*y


It still lokes quite bad. I *hate* the field projection functions, and I hate 
the '?'!! So you could simply rename you data opt fields and declare,

eta :: (?opt:: Options) => Double
eta = etaF ?opt

epsilon :: (?opt:: Options) => Double
epsilon = epsilonF ?opt

Now f could be written like:
f :: (?opt::Options)=> Double -> Double -> Double
f x y = eta*x - epsilon^2*y

Which differs from the first f function only in the context.
It is *almost* good enough for me :-)
"Why the almost?" you ask... 

Well, implicit parameters are not only non-standard features, but also 
experimental features (right?), so you they can change anytime.
--------------------------------------------------------------------------------------
NOTE: some of you might wanna quit reading here, I keep complaining about 
this stuff, you are probably tired of it :-)
--------------------------------------------------------------------------------------

In a couple of days you will also want to use more than one record, because 
grouping certain constants together doesn't feel right, and contexts will get 
bigger.
Also, you will want to use global variables and instead of a record you will 
use an STRef to a record, and very small signatures will have in they're 
context something like: (?opt :: STRef s Opt). And then you will need to 
update some option fields, and you will want to use modifySTRef, and you will 
need to create an applyField function to every damn field of the record...
So you will start asking
1. (when) will we have implicit contexts available? 
2. wouldn't it be good to have, besides the data projection functions, some 
update  and apply field functions, automaticly derived when declaring the 
data type? [yes am actually *asking* if *anyone agrees* with me? haven't had 
any feedback on this one, so I don't no wether it is a good or just plain 
dumb idea]

IMVHO, it is of extreme importance and *urgent* to get implicit parameters 
right. This question about how to use this 'user difined constants' is a 
*simple* question and should have a *very simple* and standard answer.
The same goes to global variables. We need them in certain situations and it 
is supposed to be, and it can be from my experience, *simple*.
J.A.