Übergeben Sie Zeiger auf ein Array in Haskell zu einer C-Funktion
Frage
Ich habe den folgenden C-Code:
#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];
}
Der Versuch, Port diesen Fortran-Code zu 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
Wie kann ich Array definieren und! oder !!! für den folgenden Code arbeiten?
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
Lösung
Ich schlage vor, diese:
{-# 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
aber, spezifische Fragen zu beantworten:
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
Ich schlage vor, verwenden Hoogle die Funktionen, die Sie benötigen.
Andere Tipps
Gibt die Summe, Benutzerzeit und Systemzeit als Tupel. Beachten Sie, dass etime einen Zeiger nimmt zu schweben, nicht verdoppeln, so stellen Sie Ihre Arten einig:
{-# 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
In Anbetracht des folgende zusätzliche Haskell-Modul:
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
Und nun können wir Anschluss dieses Stück Fortran-Code:
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
Wort für Wort zu 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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow