Конвертировать FD в Handle

Я хотел бы открыть псевдо-tty и использовать полученный подчиненный терминал для подключения к stdin/stdout в подпроцессе. openPseudoTerminal дает мне IO (System.Posix.Types.Fd, System.Posix.Types.Fd), который я пытался перевести в пару ручек, используя fdToHandle в GHC.IO.Handle.Fd (Специфично для GHC, но я не смог найти другую такую ​​функцию). Тем не менее, я получаю следующее:

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

Любые идеи, как я перехожу между этими двумя (предположительно похожими) вещами?

Для бонусных баллов это даст мне IO (IO Handle, IO Handle) - Есть ли аккуратный способ преобразовать его в IO (Handle, Handle)?

2 ответа

Решение

openPseudoTerminal находится в пакете Unix, который также обеспечивает fdToHandle с соответствующим типом в System.Posix.IO,

Я добавлю лучший однострочник, который я когда-либо придумал, чтобы разобраться с парой IO Handles:

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

или же:

getHandles =
  openPseudoTerminal >>= uncurry (ap . fmap (,)) . join (***) fdToHandle

Вы можете попросить GHCI предоставить информацию об этих типах -

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

поэтому они по существу идентичны, за исключением того, что newtype а другой type, Так что функции преобразования (я рекомендую выбирать лучшие имена)

convert :: FD -> Fd
convert = Fd

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

RE ваш вопрос о конвертации из IO (IO Handle, IO Handle) в IO (Handle,Handle) вы могли бы сделать это явно

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

но лучшим способом было бы избежать креатин IO (IO Handle, IO Handle) на первом месте. Так как ваши типы

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

ты мог бы сделать

getHandles :: IO (Handle, Handle)
getHandles = do
  (Fd a, Fd b) <- openPseudoTerminal
  a'           <- fdToHandle a
  b'           <- fdToHandle b
  return (a', b')
Другие вопросы по тегам