Quantcast

Force single evaluation?

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Force single evaluation?

Axel Jantsch

Hello,

I call a C function from a Haskell program. I am using unsafePerformIO
to use it outside a monad.

Even though the C function does not have any side effect, I absolutely
don't want to evaluate it more than once for performance reasons. But my
impression is that it is evaluated several times.

1. Can I monitor somehow how often it is evaluated?
2. Can I ensure that the function is evaluated only once?


I am using ghc 6.4.1

I ma grateful for any hint!

Regards,
Axel

--
Phone: +46 8 790 4124, Email: [hidden email], Web: www.it.kth.se/~axel

--

---
Phone: +46 8 790 4124, Email: [hidden email], Web: www.imit.kth.se/~axel
_______________________________________________
FFI mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/ffi
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Force single evaluation?

Malcolm Wallace
"Axel Jantsch" <[hidden email]> wrote:

> I call a C function from a Haskell program. I am using unsafePerformIO
> to use it outside a monad.
>
> Even though the C function does not have any side effect, I absolutely
> don't want to evaluate it more than once for performance reasons. But
> my impression is that it is evaluated several times.
>
> 1. Can I monitor somehow how often it is evaluated?

You could wrap it (in C) with another function that keeps a counter of
invocations in a static local variable.

    result_t  originalFn (arg1_t arg1, arg2_t arg2);
    result_t  wrappedFn  (arg1_t arg1, arg2_t arg2) {
      static int i = 0;
      i++;
      fprintf(stderr,"originalFn called %d times\n",i);
      return originalFn(arg1,arg2);
    }

> 2. Can I ensure that the function is evaluated only once?

How about stating in the type of the FFI decl that the C function is
pure (even if it is not)?  Then be sure to bind its result in only one
place.  That should guarantee it is called only once.

    foreign import ccall originalFn :: Arg1T -> Arg2T -> IO ResultT
becomes
    foreign import ccall originalFn :: Arg1T -> Arg2T -> ResultT

Regards,
    Malcolm
_______________________________________________
FFI mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/ffi
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Force single evaluation?

Axel Jantsch


I tried both alternatives:

foreign import ccall originalFn :: Arg1T -> Arg2T -> IO ResultT

foreign import ccall originalFn :: Arg1T -> Arg2T -> ResultT


but in both cases the C function originalFn is called several times for
the same arguments. And it is bound only in one place.

I don't understand why.
Maybe the problem is that the data marshaling has to be done within the
monad?

My simplified codes is as follows:

f :: InparT -> IO CInt
f inPar = do
          inP <- malloc
          poke inP inPar

          r <- cfun inP

          free inP
          return r

foreign import ccall "cfun" :: Ptr InparT -> IO CInt

So even if I make cfun pure (which it is), the enclosing function f is
not.

Shall I pretend f is pure and wrap it into unsafePerformIO?

Regards,
Axel

Malcolm Wallace <[hidden email]> wrote:

> "Axel Jantsch" <[hidden email]> wrote:
>
> > I call a C function from a Haskell program. I am using unsafePerformIO
> > to use it outside a monad.
> >
> > Even though the C function does not have any side effect, I absolutely
> > don't want to evaluate it more than once for performance reasons. But
> > my impression is that it is evaluated several times.
> >
> > 1. Can I monitor somehow how often it is evaluated?
>
> You could wrap it (in C) with another function that keeps a counter of
> invocations in a static local variable.
>
>     result_t  originalFn (arg1_t arg1, arg2_t arg2);
>     result_t  wrappedFn  (arg1_t arg1, arg2_t arg2) {
>       static int i = 0;
>       i++;
>       fprintf(stderr,"originalFn called %d times\n",i);
>       return originalFn(arg1,arg2);
>     }
>
> > 2. Can I ensure that the function is evaluated only once?
>
> How about stating in the type of the FFI decl that the C function is
> pure (even if it is not)?  Then be sure to bind its result in only one
> place.  That should guarantee it is called only once.
>
>     foreign import ccall originalFn :: Arg1T -> Arg2T -> IO ResultT
> becomes
>     foreign import ccall originalFn :: Arg1T -> Arg2T -> ResultT
>
> Regards,
>     Malcolm
> _______________________________________________
> FFI mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/ffi
>

--
Phone: +46 8 790 4124, Email: [hidden email], Web: www.it.kth.se/~axel
_______________________________________________
FFI mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/ffi
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Force single evaluation?

Sven Panne
Am Mittwoch, 20. Dezember 2006 16:10 schrieb Axel Jantsch:

> [...] My simplified codes is as follows:
>
> f :: InparT -> IO CInt
> f inPar = do
>           inP <- malloc
>           poke inP inPar
>
>           r <- cfun inP
>
>           free inP
>           return r

This can be simplified to 'flip with cFun' (malloc/free pair => alloca,
alloca/poke => with).

> [...] So even if I make cfun pure (which it is), the enclosing function f is
> not.

This depends on the viewpoint: Unless malloc fails, f will return the same
value for the same argument, so it can be considered pure.

> Shall I pretend f is pure and wrap it into unsafePerformIO?

You can do this, but you still depend on the compiler/interpreter not doing
any funny transformations which could duplicate an application of f. I don't
think that this will be a problem in practice, but to be on the safe side you
could memoize f or cFun and perhaps even a 1-element cache might be enough to
avoid all this trickery.

Cheers,
   S.
_______________________________________________
FFI mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/ffi
Loading...