From axel at kth.se Mon Dec 18 11:09:45 2006 From: axel at kth.se (Axel Jantsch) Date: Mon Dec 18 11:07:07 2006 Subject: Force single evaluation? Message-ID: <200612181609.kBIG9juu014236@bee.imit.kth.se> 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: axel@kth.se, Web: www.it.kth.se/~axel -- --- Phone: +46 8 790 4124, Email: axel@imit.kth.se, Web: www.imit.kth.se/~axel From Malcolm.Wallace at cs.york.ac.uk Mon Dec 18 11:50:28 2006 From: Malcolm.Wallace at cs.york.ac.uk (Malcolm Wallace) Date: Mon Dec 18 11:52:15 2006 Subject: Force single evaluation? In-Reply-To: <200612181609.kBIG9juu014236@bee.imit.kth.se> References: <200612181609.kBIG9juu014236@bee.imit.kth.se> Message-ID: <20061218165028.7d687f1a.Malcolm.Wallace@cs.york.ac.uk> "Axel Jantsch" 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 From axel at kth.se Wed Dec 20 10:10:00 2006 From: axel at kth.se (Axel Jantsch) Date: Wed Dec 20 10:07:20 2006 Subject: Force single evaluation? In-Reply-To: Message from Malcolm Wallace of "Mon, 18 Dec 2006 16:50:28 GMT." <20061218165028.7d687f1a.Malcolm.Wallace@cs.york.ac.uk> Message-ID: <200612201510.kBKFA0Si019676@bee.imit.kth.se> 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 wrote: > "Axel Jantsch" 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 > FFI@haskell.org > http://www.haskell.org/mailman/listinfo/ffi > -- Phone: +46 8 790 4124, Email: axel@kth.se, Web: www.it.kth.se/~axel From sven.panne at aedion.de Thu Dec 21 06:27:06 2006 From: sven.panne at aedion.de (Sven Panne) Date: Thu Dec 21 06:24:14 2006 Subject: Force single evaluation? In-Reply-To: <200612201510.kBKFA0Si019676@bee.imit.kth.se> References: <200612201510.kBKFA0Si019676@bee.imit.kth.se> Message-ID: <200612211227.06681.sven.panne@aedion.de> 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.