FW: Haskell accumulator
Dominic Cooney
dominic@dcooney.com
Fri, 14 Jun 2002 08:29:55 +1000
Paul Graham is collecting canonical accumulator generators at
http://www.paulgraham.com/accgen.html , and has Dylan, E, JavaScript,
various dialects Lisp, Lua, Rebol, Ruby, Perl, Python and Smalltalk.
Could the serious Haskellers comment on this attempt of mine?
foo n = do
n' <- newIORef n
return (\i -> do { modifyIORef n' (i+); readIORef n' })
This is all related to arguments about the benefits of succinctness and
expressivity in programming languages.
Dominic Cooney
-----Original Message-----
From: Paul Graham [mailto:pg@archub.org]
Sent: Thursday, 13 June 2002 11:17 PM
To: dominic@dcooney.com
Subject: Re: Haskell accumulator
Would this (if the type signature is unnecc) then be the
canonical def in Haskell?
foo n = do
n' <- newIORef n
return (\i -> do { modifyIORef n' (i+); readIORef n' })
--Dominic Cooney wrote:
> This is a multi-part message in MIME format.
>
> ------=_NextPart_000_0001_01C212A8.F2F6A010
> Content-Type: text/plain;
> charset="us-ascii"
> Content-Transfer-Encoding: 7bit
>
> If you are still collecting these Revenge of the Nerds accumulators,
> here it is in literate Haskell:
>
> > mkAccum :: (Num a) => a -> IO (a -> IO a)
> > mkAccum n = do
> > n' <- newIORef n
> > return (\i -> do { modifyIORef n' (i+); readIORef n' })
>
> There are a couple of interesting things here; firstly the (Num a) =>
is
> an example of Haskell's type classes.
>
> The second is the 'IO' written everywhere. Haskell is pure, and IO is
> the library-sanctioned state monad. Thus mkAccum and the accumulator
> itself evaluate to "IO things" since they involve mutable state.
>
> The only other interesting thing about the type signature is that it
is
> completely unnecessary. The compiler infers the most general type. The
> programmer can write explicit type signatures to narrow the type of a
> function, or (more commonly) have the compiler provide a sanity check.
>
> 'Return' is unusual too-- it wraps things in the IO monad. Ordinarily
it
> is not required, e.g.
>
> > incr n = \x -> n + x
>
> Although this could simply be written as a partial application, like:
>
> > incr n = (+) n
>
> A whole test program is attached re: the accumulator.
>
> On another note, I am eagerly awaiting the arrival of ANSI Common Lisp
> from Amazon. I may be converted yet.
>
> Dominic Cooney
>
>
> ------=_NextPart_000_0001_01C212A8.F2F6A010
> Content-Type: application/octet-stream;
> name="accum.lhs"
> Content-Transfer-Encoding: 7bit
> Content-Disposition: attachment;
> filename="accum.lhs"
>
> This can be built with:
>
> ghc -fglasgow-exts -package lang --make accum.lhs -o accum
>
> GHC is available from http://www.haskell.org/ghc .
>
>
> > module Main (main) where
>
> Haskell is pure-- the state of the world is in the IO monad. Hence
> the accumulator requires these imports.
>
> > import IOExts (IORef, newIORef, readIORef, modifyIORef)
>
>
> The accumulator.
>
> > mkAccum :: (Num a) => a -> IO (a -> IO a)
> > mkAccum n = do
> > n' <- newIORef n
> > return (\i -> do { modifyIORef n' (i+); readIORef n' })
>
>
> Small test program.
>
> > main :: IO ()
> > main = do
> > acc <- mkAccum 42
> > x <- acc 1
> > put x
> > x <- acc 2
> > put x
>
>
> Put is a small function that prints something.
>
> > put :: (Show a) => a -> IO ()
> > put = putStrLn.show
> ------=_NextPart_000_0001_01C212A8.F2F6A010--
>