مؤشر تمرير إلى صفيف في Haskell إلى وظيفة C
سؤال
لدي رمز C التالي:
#include <sys/times.h>
#include <time.h>
float etime_( float *tarray )
{ struct tms buf;
times( &buf );
tarray[0] = 1.0 * buf.tms_utime / CLOCKS_PER_SEC;
tarray[1] = 1.0 * buf.tms_stime / CLOCKS_PER_SEC;
return tarray[0] + tarray[1];
}
محاولة ميناء هذا الكود Fortran إلى Haskell:
PROGRAM Test
IMPLICIT NONE
REAL t, ta(2), etime
INTEGER i
DOUBLE PRECISION x
do i = 1, 10000
x = sin( cos( i * 1.0 d0 ) )
print *, x
enddo
ta(1) = 0.0d0
ta(2) = 0.0d0
t = etime( ta )
PRINT *, 'user time: ', ta(1)
PRINT *, 'system time: ', ta(2)
PRINT *, 'process time: ', t
END
كيف يمكنني تحديد الصفيف و! أو !!! للحصول على رمز أدناه للعمل؟
module Main where
import GHC.Ptr
import GHC.Prim
import System.IO.Unsafe
import Control.Monad
foreign import ccall etime_ :: Ptr Double → IO Double
etime = etime_
main :: IO Int
main = do
mapM_ (print . sin . cos . (* (1.0 :: Double)) . fromIntegral) [1..10000 :: Int]
ta ← array 2
t ← etime ta
putStrLn $ "user time: " ++ show (ta !!! 0)
putStrLn $ "system time: " ++ show (ta !!! 1)
putStrLn $ "process time: " ++ show t
return 0
array :: Int → IO (Ptr a)
array size = undefined
(!) :: Ptr a → Int → IO a
(!) = undefined
(!!!) :: Ptr a → Int → a
(!!!) = undefined
المحلول
أقترح هذا:
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.Marshal.Array (allocaArray, peekArray)
import Foreign.Ptr (Ptr)
foreign import ccall etime_ :: Ptr Float -> IO Float
main :: IO ()
main = do
mapM_ (print . sin . cos . (* (1.0 :: Double)) . fromIntegral) [1..10000 :: Int]
allocaArray 2 $ \ta -> do
ptime <- etime_ ta
[utime, stime] <- peekArray 2 ta
putStrLn $ "user time: " ++ show utime
putStrLn $ "system time: " ++ show stime
putStrLn $ "process time: " ++ show ptime
ولكن للإجابة على أسئلتك المحددة:
array :: Storable a => Int -> IO (Ptr a)
array = mallocArray
(!) :: Storable a => Ptr a -> Int -> IO a
(!) = peekElemOff
(!!!) :: Storable a => Ptr a -> Int -> a
(!!!) ptr = unsafePerformIO . peekElemOff ptr
أقترح استخدام Hoogle للعثور على الوظائف التي تحتاجها.
نصائح أخرى
إرجاع المبلغ، وقت المستخدم، ووقت النظام كقوام. لاحظ أن الادئة تأخذ مؤشرا لتعويمها، وليس مضاعفة، لذا فإن جعل أنواعك توافق على:
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
import Foreign (Ptr)
import Foreign.Marshal.Array (allocaArray,peekArray)
import Control.Monad (mapM_)
foreign import ccall etime_ :: Ptr Float -> IO Float
etime :: IO (Float, Float, Float)
etime = do
allocaArray 2 $ \ta -> do
t <- etime_ ta
[user,sys] <- peekArray 2 ta
return (t,user,sys)
main :: IO Int
main = do
mapM_ (print . sin . cos . (* (1.0 :: Double)) . fromIntegral) [1..10000 :: Int]
(t,user,sys) <- etime
putStrLn $ "user time: " ++ show user
putStrLn $ "system time: " ++ show sys
putStrLn $ "process time: " ++ show t
return 0
بالنظر إلى وحدة Haskell إضافية التالية:
module AllocSymbols (
(↑≣), -- mallocArray
(≣⊠), -- free
(≣→), -- peekElemOff
(≣←), -- pokeElemOff
(⥱), -- peekElemOff unsafe
(⥅), -- advancePtr
) where
import GHC.Ptr
import System.IO.Unsafe
import Foreign.Storable
import Foreign.Marshal.Alloc (free)
import Foreign.Marshal.Array
(↑≣) :: Storable a ⇒ Int → IO (Ptr a)
(↑≣) = mallocArray
(⥱) :: Storable a ⇒ Ptr a → Int → a
a ⥱ i = unsafePerformIO $ peekElemOff a i
(≣→) :: Storable a ⇒ Ptr a → Int → IO a
(≣→) = peekElemOff
(≣←) :: Storable a ⇒ Ptr a → Int → a → IO ()
(≣←) = pokeElemOff
(⥅) :: Storable a ⇒ Ptr a → Int → Ptr a
(⥅) = advancePtr
(≣⊠) :: Ptr a → IO ()
(≣⊠) = Foreign.Marshal.Alloc.free
والآن يمكننا مرفذ هذه القطعة من رمز FORTRAN:
PROGRAM Test
IMPLICIT NONE
REAL t, ta(2), etime
INTEGER i
DOUBLE PRECISION x
do i = 1, 10000
x = sin( cos( i * 1.0 d0 ) )
print *, x
enddo
ta(1) = 0.0d0
ta(2) = 0.0d0
t = etime( ta )
PRINT *, 'user time: ', ta(1)
PRINT *, 'system time: ', ta(2)
PRINT *, 'process time: ', t
END
كلمة للكلمة إلى haskell:
module Main where
import GHC.Ptr
import AllocSymbols
import Control.Monad
foreign import ccall etime_ :: Ptr Float → IO Float
main :: IO ()
main = do
mapM_ (print . sin . cos . (* (1.0 :: Double)) . fromIntegral) [1 .. 10000 :: Int]
ta ← (2 ↑≣) -- ta :: Ptr Float
(ta ≣← 0) 0.0
(ta ≣← 1) 0.0
t ← etime_ ta
putStrLn $ " user time: " ++ show (ta ⥱ 0)
putStrLn $ " system time: " ++ show (ta ⥱ 1)
putStrLn $ " process time: " ++ show t
(ta ≣⊠) -- optional in this case
لا تنتمي إلى StackOverflow