[Haskell-cafe] unsafePerformIO usage

Serge D. Mechveliani mechvel at botik.ru
Sun May 6 22:21:15 CEST 2012


People,
can anybody explain what incorrect may happen with the following 
program which uses exchange through two Unix pipes and  
unsafePerformIO ?

The pipes are created by the Unix commands
                                  mkfifo toA;  mkfifo fromA

gcc iface.c       compiles the C program to  a.out.
ghc --make Main   compiles the Haskell program by GHC to  ./Main

Run on the second terminal          > ./iface 
Run on the first terminal           > ./Main
It prints the result to the screen.

In  Main.hs,  the function   iface :: String -> String

is defined via  hPutStr, hGetLine, hFlush,  unsafePerformIO.  It

  outputs  str :: String  to the pipe  toA;
  the process  iface  (programmed in C)  waits for  delay  and returns 
  the respond string  through the pipe  fromA;
  iface  inputs this respond  string.  

So far, I put the respond string to be the same string, 
I think, this is not essential, but another map can be considered.

Assume that the parallel computation is not allowed.

In the below `main', I tried 
             f ss  where
                   ss = [iface $ shows i "\n" | i <- [1 .. 4]],
                   f [s1, s2, s3, s4] = [s3++s1, s3++s2, s1++s2],
and it works correct. 
The question is: 
    what a simple definition is possible for  f  which will evaluate 
    incorrect?

Is this true that  unsafePerformIO  is _safe_ for all  f  in this 
context?

The `delay' constant can be edited in  fifo.c. 
See both sources below.

Please, copy the respond to  mechvel at botik.ru

Thanks,

------
Sergei
mechvel at botik.ru




------------------------------------------------------------------------
import System.IO (IOMode(..), IO(..), Handle, openFile, hPutStr, 
                                              hGetLine, hFlush)
import System.IO.Unsafe (unsafePerformIO)

dir = showString "/home/mechvel/haxiom/unsafeTest/"

-- openFile :: FilePath -> IOMode -> IO Handle 
-- hPutStr  :: Handle -> String -> IO () 
-- hGetLine :: Handle -> IO String

toA_IO   = openFile (dir "toA")   WriteMode  :: IO Handle
fromA_IO = openFile (dir "fromA") ReadMode  
toA      = unsafePerformIO toA_IO   
fromA    = unsafePerformIO fromA_IO

initIO :: IO (Handle, Handle)
initIO = do
         to   <- toA_IO
         from <- fromA_IO
         return (to, from)

ifaceIO :: (Handle, Handle) -> String -> IO String
ifaceIO    (h1,     h2)        str = do
                                     hPutStr h1 str
                                     hFlush h1
                                     str' <- hGetLine h2
                                     return str'
iface :: String -> String
iface str =  unsafePerformIO $ ifaceIO (toA, fromA) str

main = putStr $ shows [s3++s1, s3++s2, s1++s2] "\n"
       where
       ss@[s1, s2, s3, s4] = [iface $ shows i "\n" | i <- [1 .. 4]]


-- The C program  fifo.c ---------------------------------------------

#include <stdio.h>
#include <string.h>  
#define BOUND 64
static  char  str[BOUND];
main() 
{
  int l, i;  long j;  FILE *toA, *fromA;

  toA = fopen("/home/mechvel/haxiom/unsafeTest/toA", "r");
  if (toA == NULL) {perror("fopen(toA, r)  failed:  ");  return;};   
  fromA = fopen("/home/mechvel/haxiom/unsafeTest/fromA", "w");
  if (fromA == NULL) {perror("fopen(fromA, w) failed:  "); return;};

  for (;;) 
  {
    if (fgets(str, BOUND, toA) == NULL) { 
       perror("fgets(str, bound, toA)  failed:  "); return;
    };
    j = 20000000;              // delay.  edit it
    while (j > 0) {j = j-1;};

    fputs(str, fromA);
    fflush(fromA);
  };
  return;
} 







More information about the Haskell-Cafe mailing list