[Haskell-cafe] unsafePerformIO usage

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

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 

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

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

Please, copy the respond to  mechvel at botik.ru


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"
       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];
  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);

More information about the Haskell-Cafe mailing list