2009-06-15 19 views
3

Je le code C suivant:Passe pointeur vers un tableau dans Haskell à C Fonction

#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]; 
} 

Essayer de porter ce code 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 

Comment puis-je définir tableau et ! ou !!! pour que le code ci-dessous fonctionne?

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 

Répondre

2

Je propose ceci:

{-# 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 

mais pour répondre à vos questions:

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 

Je suggère d'utiliser Hoogle pour trouver les fonctions dont vous avez besoin.

0

Renvoie la somme, l'heure utilisateur et l'heure système sous la forme d'un tuple. Notez que etime prend un pointeur à flotter, pas deux fois, alors faites vos types d'accord:

{-# 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 
+0

Y a-t-il une différence de précision entre float et double en haskell? sont les deux primitives ou est flottant pour doubler comme entier à int? –

+0

Oui: le Prelude définit Float et Double pour les nombres à virgule flottante simple et double précision respectivement. Voir la section Numéros du Rapport Haskell: http://www.haskell.org/onlinereport/basic.html#sect6.4 –

-2

Compte tenu du module Haskell supplémentaire suivant:

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 

Et maintenant, nous pouvons le port ce morceau de 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 

mot pour mot à 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 
+1

aimez-vous les opérateurs autant? Je pense que le code serait plus novice-friendly avec les noms de fonction standard .. – yairchu

+0

Je pense que je suis assez étrange et étrange o__O. Je les aime tellement ~~~ beaucoup! Et parce que mon code Haskell est principalement pour moi, je les utilise généreusement *^o^* !! S'il m'arrive de collaborer avec d'autres sur un projet commun, je m'assurerai certainement de garder les choses amicales et maintenables et éviterai d'introduire autant d'indirections. –