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.