Haskell IO (String) и String - PullRequest
       12

Haskell IO (String) и String

7 голосов
/ 08 июля 2011

Я хочу написать функции и поместить результат в строку.

Я хочу функцию:

read' :: FilePath -> String

Я использую:

:t readFile
readFile :: FilePath -> IO String

Я делаю:

read' :: IO ()
read' = do
     str <- readFile "/home/shk/workspace/src/test.txt" 
     putStrLn str

Я хочу спросить, str это строка или нет?

Мы знаем, что:

:t putStrLn
putStrLn :: String -> IO ()

Тогда почему я не могу:

read' :: String
read' = do
     str <- readFile "/home/shk/workspace/lxmpp/src/test.txt" 
     str

Я получаю сообщение об ошибке:

 Couldn't match expected type `[t0]' with actual type `IO String'
    In the return type of a call of `readFile'
    In a stmt of a 'do' expression:
        str <- readFile "/home/shk/workspace/lxmpp/src/test.txt"
    In the expression:
      do { str <- readFile "/home/shk/workspace/src/test.txt";
           str }

Спасибо.

Ответы [ 4 ]

10 голосов
/ 08 июля 2011

Просто для того, чтобы приглушить немного больше, в то время как другие ответы совершенно правильны, я хочу кое-что подчеркнуть: что-то с типом IO String - это не просто строка, к которой система типов не позволит вам добраться напрямую.Это вычисление, которое выполняет ввод / вывод, чтобы получить строку для вас .Применение readFile к пути к файлу не возвращает значение String больше, чем размещение стейка рядом с мясорубкой волшебным образом превращает их в гамбургер.

Когда у вас есть такой код:

foo = do let getStr = readFile "input.txt"
         s1 <- getStr
         s2 <- getStr
         -- etc.

Это не значит, что вы «вынимаете строку из getStr дважды».Это означает, что вы выполняете вычисления дважды и можете легко получить разные результаты между ними.

6 голосов
/ 09 июля 2011

Думаю, никто не ответил на этот очень важный вопрос:

Я хочу спросить str это строка или нет?

Я постараюсь.

Тип переменной str равен String, да. Однако область действия этой переменной очень ограничена. Я думаю, что для понимания необходимо разобраться в нотации:

read' = readFile "/home/shk/workspace/src/test.txt" >>= (\str -> putStrLn str)

Я думаю, здесь становится более понятно, почему str недостаточно хорош. Это аргумент функции, которую вы передаете >>=. Его значение становится доступным только тогда, когда кто-то вызывает вашу функцию, что происходит только тогда, когда выполняется действие IO, содержащее ее.

Кроме того, тип read' :: IO () определяется не столько putStrLn str, сколько типом возврата оператора >>=. Взгляните на это (специально для монады IO):

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

Вы можете видеть, что результатом всегда является действие IO b, поэтому попытка изменить любой из аргументов не поможет.

Вы можете прочитать учебник по монадам, если хотите понять, почему этот тип такой. За этим стоит интуиция: вы не можете выполнить действие без выполнения действия.

И с практической стороны вопроса использовать значение, возвращаемое некоторым действием, вместо попытки сделать use (extractValue inputAction), что не имеет смысла, потому что extractValue невозможно, попробуйте inputAction >>= use, если ваш use включает ввод-вывод или fmap use inputAction, если нет.

4 голосов
/ 08 июля 2011

Вы должны использовать return str в read', если хотите, чтобы он возвращал str вместо ().Вы не можете удалить IO из типа read', так как это не чистая функция.Чтобы лучше понять, как работает ввод / вывод в Haskell, я рекомендую вам прочитать учебник .

1 голос
/ 08 июля 2011

В качестве более подробной причины, почему: он допускает примеси.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...