В чем разница между строкой ввода-вывода и обычной строкой в ​​Haskell - PullRequest
1 голос
/ 18 марта 2010

Есть ли такая разница от IO String до String

Я хочу взять некоторые строковые значения из ввода-вывода.

Может кто-нибудь рассказать мне об этой проблеме. я невежественен

Ответы [ 2 ]

6 голосов
/ 18 марта 2010

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

Или: вы пишете так, как будто вы определили или изолировали строку, но вы этого не сделали. Итак, вы определили или изолировали действие , которое возвращает строку . Отдельные случаи выполнения этого действия будут возвращать разные строки.

Предположительно, вы пытаетесь определить более сложное действие - что-то типа IO Blah - возможно, что-то типа IO () типа чего-то, что может быть скомпилировано в исполняемый файл. Идея состоит в том, что в более сложном действии, получив значение String, выполнив действие типа IO String - действие, которое вы до сих пор определили - исполнитель сложного действия продолжит выполнять то, что зависит только от того, что это значение. Это что-то, представленное функцией типа String -> IO Blah - возможно String -> IO ()

Конечно, такая функция не принимает значения IO String (то есть действия, которые возвращают строки) в качестве аргументов, а String значения в качестве аргументов. Мы не можем присоединиться к ним напрямую.

Чтобы перейти от вашего действия , которое возвращает строку - ваше значение IO String - и функцию 'String -> IO Blah', к чему-то новому - действие , которое возвращает бла - мы присоединяемся к ним через функцию >>=. Специально для этого случая >>= имеет тип IO String -> (String -> IO Blah) -> IO Blah - это может быть IO String -> (String -> IO ()) -> IO ()

Итак, чтобы взять самый тривиальный пример пары таких вещей, рассмотрим getLine и putStrLn.

getLine - это действие по определению, какая строка была только что введена - она ​​имеет тип IO String.

Можно сказать, что putStrLn выводит значение String на экран, а затем возвращает к левому полю . Но это поверхностно: то, что определенное действие будет сделано, зависит от спецификации значения String, поэтому оно имеет тип String -> IO(). То есть: putStrLn ничего не делает, это функция, которая отображает строки на вещи, которые могут быть выполнены. Таким образом, как обычно, вы можете определить значение в его типе диапазона (действия, то есть IO () s), следуя за знаком функции с именем чего-либо в типе домена (строки, т.е. String). Таким образом, комбинация putStrLn "Gee whiz" называет определенное действие, что-то типа IO ().

ghci будет выполнять такие действия на лету, поэтому для любой строки, такой как «Gee whiz», вы можете написать putStrLn "Gee whiz", и она немедленно «выполнит это действие» - действие, написав «Gee whiz» для экран и возвращаясь к левому полю.

Prelude> putStrLn "Gee whiz"
Gee whiz
Prelude> 

Аналогично, односимвольная строка, в которой есть только символ Unix \BEl, - это строка, которую мы называем '\BEl':[] или ['\BEL'] или "\BEL". Для этой строки в качестве аргумента putStrLn имеет слышимый совершенно другой вид действия для значения. Мы получаем

* * 1068

Здесь вы услышите звонок Unix, прежде чем он вернется к левому полю. Это довольно слабая аудиопрограмма, но вы здесь. ghci означает выполнение действия звучания звонка Unix , действия, которое вы назвали словами putStrLn "\BEL" перед нажатием возврата.

Так или иначе, getLine - это значение типа IO String, и вы хотите «взять это строковое значение из IO». Конечно, он еще не существует, это зависит от того, что пользователь вводит. Но мы можем рассмотреть, что программа должна делать с таким значением, когда оно ее получает. Мы можем указать это, указав функцию от строки до действия, например putStrLn. Таким образом, мы можем определить полное действие, которое «принимает значение» и использует его определенным образом, составляя их с >>= или do нотацией сахара.

Самым тривиальным случаем будет что-то вроде echo:

echo :: IO ()
echo = getLine >>= putStrLn

или эквивалентно

echo = getLine >>= (\x -> putStrLn x)

или do: 1091 *

echo = do 
     the_string_i_want_to_take <- getLine
     putStrLn the_string_i_want_to_take

или менее нелепо:

echo = do 
     x <- getLine
     putStrLn x

Конечно, вы хотите "взять строку" и, возможно, возиться с ней до окончания.

reverseEcho :: IO ()
reverseEcho = getLine >>= (\x -> putStrLn (reverse x))

или более компактно:

reverseEcho = getLine >>= (putStrLn . reverse)

или в do нотации:

reverseEcho = do 
        the_string_i_want_to_take <- getLine
        putStrLn (reverse the_string_i_want_to_take)

или менее нелепо:

reverseEcho = do 
        x <- getLine
        putStrLn (reverse  x)

если вы хотите думать о «обращении строки» как о чем-то, что делается со строкой между получением и печатью, вы можете написать:

reverseEcho = do 
        the_string_i_want_to_take <- getLine
        the_string_after_i_have_processed_it <- return (reverse the_string_i_want_to_take)
        putStrLn (the_string_after_i_have_processed_it)

или

reverseEcho = do
        x <- getLine
        y <- return x
        putStrLn y

или эквивалентно

reverseEcho = (getLine >>= (return . reverse)) >>= putStrLn 

Здесь круглые скобки не нужны, потому что уровни приоритета для . и >>= соответственно оптимизированы. Но (getLine >>= (return . reverse)) - это просто другое имя «действия, которое возвращает строку», значение IO String, которое не является самой строкой. Вы не можете применить функцию String -> Whatever непосредственно к ней, чтобы получить Whatever, но вы можете комбинировать ее с функцией от строк до действий через >>=.

Аналогично

reverseFileAA :: IO ()
reverseFileAA = readFile "AA.txt" >>= writeFile "reversedAA.txt" . reverse

- это действие записи файла с именем "reversedAA.txt" с обратной строкой, найденной в AA.txt, какой бы она ни была, и может быть записана

reverseFileAA = do
     old_file_contents <- readFile "AA.txt"
     new_file_contents <- return (reverse old_file_contents)
     writeFile "reversedAA.txt" old_file_contents
4 голосов
/ 18 марта 2010

IO String - это строка в IO-монаде. Если функция в IO-Monad возвращает IO String, вы получаете String, выполнив:

do str <- ioFunc

Функция находится в IO-Monad, когда ей необходим IO-доступ и она должна возвращать типы ввода-вывода.

...