hPutStrLn со строкой ввода-вывода?

У меня есть функция, которую я должен использовать, и она называется:

hPutStrLn

Эта функция имеет тип:

hPutStrLn::Handle -> String -> IO ()

И то, что я хотел сделать, это использовать командную строку оболочки grep и получить вывод и передать в переменную String hPutStrLn,

Например:

 tryA (arrIO (\s -> hPutDocument (\h-> hPutStrLn h (readProcess "grep" ["-n",s,"camera2.owl"] ""))))

Но проблема в том, что мой readProcess имеет тип IO String, который должен быть String, если я хочу использовать функцию hPutStrLn! И я не знаю, как я могу решить это... Итак, у меня есть несколько вопросов: -Могу ли я извлечь строку из строки ввода-вывода? - Если я не могу, есть ли другой способ сделать это?

функция hPutDocument

hPutDocument      :: (Handle -> IO ()) -> IO ()
      hPutDocument action
          | isStdout
              = do
                hSetBinaryMode stdout (not textMode)
                action stdout
                hSetBinaryMode stdout False
          | otherwise
              = do
                handle <- ( if textMode
                            then openFile
                            else openBinaryFile
                          ) dst WriteMode
                action handle
                hClose handle

isStdout  = null dst || dst == "-"

outFile   = if isStdout
            then "stdout"
            else show dst

1 ответ

Решение

Самый простой подход с do нотации. Вы можете определить вспомогательную функцию для передачи hPutDocument:

doGrep :: Handle -> IO ()
doGrep h =
    do
        str <- readProcess "grep" ["-n",s,"camera2.owl"] ""
        hPutStrLn h str

tryA (arrIO (\s -> hPutDocument doGrep))

Один из способов думать о том, что это позволяет вам преобразовать IO String к String, но только в рамках do блок, и весь do блок заканчивается тем, что IO тип - IO () в этом случае.

Вы не можете конвертировать IO String к String в произвольном контексте, потому что система типов Haskell разработана, чтобы помешать вам рассматривать нечистые значения, которые поступают из внешних источников, считающихся чистыми - IO Тип указывает, что значение, возможно, пришло из-за какого-то ввода-вывода.

Вы также можете использовать >>= оператор (произносится как "связать") непосредственно в вашем вызове hPutDocument:

hPutDocument (\h -> readProcess "grep" ["-n",s,"camera2.owl"] ""
                       >>= \str -> hPutrStrLn h str)

>>= имеет этот тип:

(>>=) :: IO a -> (a -> IO b) -> IO b

В этом конкретном случае a = String а также b = (),

Так вот >>= принимает IO String произведено readProcess ... и передает его второму аргументу, который является функцией, которая принимает String и производит IO (), Общий результат IO () производится вторая функция.

Запись \str -> hPutStrLn h str определяет анонимную функцию ("лямбда"), которая принимает str в качестве аргумента и дает результат hPutStrLn h str,

do примечание выше фактически переведено ("desugared") к этому компилятором.

В этом конкретном случае вы также можете сократить \str -> hPutrStrLn h str чтобы просто hPutStrLn h, и вы также можете использовать оператор обратного связывания =<< создать что-то максимально приближенное к вашему исходному коду:

hPutDocument (\h -> hPutStrLn h =<< readProcess "grep" ["-n",s,"camera2.owl"] "")

укорачивание \str -> hPutStrLn h str работает из-за частичного применения ("карри"). Функция, которая принимает несколько аргументов, может быть просто передана некоторым из них (по порядку), возвращая функцию, которая ожидает оставшиеся аргументы.

поскольку hPutStrLn имеет тип Handle -> String -> IO (), hPutStrLn h имеет тип String -> IO ()До тех пор, пока h имеет тип Handle,

Другие вопросы по тегам