[Haskell-beginners] Calling a foreign function: superlinear comlexity

Felipe Almeida Lessa felipe.lessa at gmail.com
Sun Apr 17 01:47:48 CEST 2011

On Sat, Apr 16, 2011 at 8:05 PM, Edward Z. Yang <ezyang at mit.edu> wrote:
> I suspect you want something a little more clever.  In particular, because
> replicateM uses sequence under the hood, which is quite strict: it requires
> all of the IO actions to be evaluated before evaluation continues, so you
> end up with a big list built up in memory before it gets summed by 'sum'.
> I suspect if you run it manually with something like this you might do better:
>    let loop 0 s = return s
>        loop n s = do
>            x <- c'gsl_rng_uniform rng
>            loop (n-1) (s+x)
>    print =<< loop n 0
> With an actually pure function, you can do it more nicely, but it's a bit
> more fragile that way.  Lazy IO would be another mechanism, although some
> people regard that to be a bit evil (and you'd still need to write the
> lazy IO equivalent of sequence).

You may use an iteratee for the same purpose.  Using John Millikin's
enumerator package, you can separate the function that calls the C
code in an enumerator

  import qualified Data.Enumerator as E

  enumerator :: Integer -> E.Enumerator Double IO b
  enumerator n = E.replicateM n c'gsl_mg_uniform

and the code that sums the values in an iteratee

  iteratee :: Monad m => E.Iteratee m Double
  iteratee = E.foldl' (+) 0

Calling them is as simple as

  E.run $ enumerator n $$ iteratee

but note that you can also test your iteratee (which may be more
complex than just summing) on any monad, including Identity.  But
unfortunately I don't think GHC (at least 6.12) can transform this
code into something tidy as Edward's code.  =(

Cheers! =)


More information about the Beginners mailing list