Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert FD to Handle

Tags:

linux

haskell

tty

I'd like to open a pseudo-tty and use the resulting slave terminal to connect to stdin/stdout on a subprocess. openPseudoTerminal gives me an IO (System.Posix.Types.Fd, System.Posix.Types.Fd), which I sought to translate into a pair of handles using fdToHandle in GHC.IO.Handle.Fd (GHC specific, but I couldn't find another such function). However, I get the following:

liftA (fdToHandle *** fdToHandle) openPseudoTerminal
Couldn't match type `System.Posix.Types.Fd'
               with `System.Posix.Internals.FD'

Any ideas how I convert between these two (presumably similar) things?

For bonus points, this will give me an IO (IO Handle, IO Handle) - is there a neat way to convert it to an IO (Handle, Handle)?

like image 347
Impredicative Avatar asked Feb 15 '23 08:02

Impredicative


2 Answers

openPseudoTerminal is in the unix package, which also provides an fdToHandle with the appropriate type in System.Posix.IO.

I'll throw in the best one-liner I have come up with so far, to deal with the pair of IO Handles:

getHandles :: IO (Handle, Handle)
getHandles =
  openPseudoTerminal >>= uncurry ap . (fmap (,) . fdToHandle *** fdToHandle)

or:

getHandles =
  openPseudoTerminal >>= uncurry (ap . fmap (,)) . join (***) fdToHandle
like image 152
raymonad Avatar answered Feb 23 '23 19:02

raymonad


You can ask GHCI for information about these types --

>> :i FD
type FD = Foreign.C.Types.CInt
>> :i Fd
newtype Fd = Fd Foreign.C.Types.CInt

so they are essentially identical, except that one is a newtype and the other is a type. So the conversion functions are (I recommend choosing better names)

convert :: FD -> Fd
convert = Fd

convert' :: Fd -> FD
convert' (Fd x) = x

RE your question about converting from IO (IO Handle, IO Handle) to IO (Handle,Handle) you could do this explicitly

flatten :: IO (IO a, IO a) -> IO (a,a)
flatten x = do
  (a,b) <- x
  a'    <- a
  b'    <- b
  return (a', b')

but a better way would be to avoid creatign the IO (IO Handle, IO Handle) in the first place. Since your types are

openPseudoTerminal :: IO (Fd, Fd)
fdToHandle         :: FD -> IO Handle

you could do

getHandles :: IO (Handle, Handle)
getHandles = do
  (Fd a, Fd b) <- openPseudoTerminal
  a'           <- fdToHandle a
  b'           <- fdToHandle b
  return (a', b')
like image 33
Chris Taylor Avatar answered Feb 23 '23 18:02

Chris Taylor