A newbie's proud first code

Adrian Hey ahey@iee.org
Mon, 5 Nov 2001 09:53:37 +0000


On Monday 05 November 2001  7:27 am, Luke Maurer wrote:
> -- Euler's method for solution of first-order differential equations
> -- In function arguments, the initial value problem under consideration is:
>
> -- df/dt = f'(f, t)
> -- f(0) = f0
>
> -- The euler function returns an infinite list of the values at each
> interval
> -- of length dt of the solution.
> euler                   :: (Num a) => (a -> a -> a) -> a -> a -> [a]
> euler f' dt f0          = euler' f' dt f0 0 -- t "defaults" to 0
>
> -- This function does the actual work, sparing the user from having to
> supply
> -- a value for t (which should always be 0 in the initial call, anyway)
> euler'                  :: (Num a) => (a -> a -> a) -> a -> a -> a -> [a]
> euler' f' dt f t        = f : euler' f' dt fnext (t + dt)
>         where fnext     = f + dt * (f' f t)
>
> My only issue (and it is nitpicky) is that I don't really like having to
> declare an extra function (euler') in the same scope as euler. I tried
> playing with where clauses or let expressions, but I couldn't find a way to
> make GHC happy without introducing a bunch of extra variables (since I'd
> need new versions of the arguments to euler; in euler', I just used the
> same names. Also, nested "where" doesn't work as I'd like it to.) Is there,
> in fact, a more concise way to express what I'm doing?

Well, I'm no expert in Haskell style, but some might say it's better style
to lift out the constants f' and dt as free variables in a local definition
of euler' ..

euler :: (Num a) => (a -> a -> a) -> a -> (a -> [a])
euler f' dt = euler' 0
	where euler' t f = 	let	fnext = f + dt * (f' f t)
					tnext = t + dt
				in f : euler' tnext fnext	

I think that works. I'm not sure if or why that's better but Haskeller's
seem to do this kind of thing a lot. It's good for looking smart and
confusing newbies if nothing else :-)

Regards
-- 
Adrian Hey