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
,