[英]Haskell IO (String) and String
我想編寫函數並將結果放入字符串。
我想要 function:
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 }
謝謝你。
再狡辯一點,雖然其他答案完全正確,但我想強調一點: IO String
類型的東西不僅僅是類型系統不會讓你直接得到的字符串。 它是一種執行 I/O 來為您獲取字符串的計算。 將readFile
應用於文件路徑不會返回String
值,就像將牛排放在絞肉機旁邊神奇地將它們變成漢堡包一樣。
當你有這樣的代碼時:
foo = do let getStr = readFile "input.txt"
s1 <- getStr
s2 <- getStr
-- etc.
這並不意味着您“將字符串從getStr
中取出兩次”。 這意味着您要執行兩次計算,並且可以輕松地在兩者之間獲得不同的結果。
我認為沒有人回答過這個非常重要的問題,但是:
我想問 str 是不是字符串?
我會試着去。
變量str
的類型是String
,是的。 但是,這個變量的 scope 是非常有限的。 我認為去除 do-notation 的糖分對於理解是必要的:
read' = readFile "/home/shk/workspace/src/test.txt" >>= (\str -> putStrLn str)
我認為這里更清楚為什么str
不夠好。 這是您傳遞給>>=
的 function 的參數。 它的值只有在有人調用您的 function 時才可用,只有在執行包含它的IO
操作時才會發生這種情況。
此外, read':: IO ()
的類型不是由putStrLn str
決定的,而是由運算符的返回類型>>=
決定的。 看看它(專門用於IO
monad):
(>>=) :: IO a -> (a -> IO b) -> IO b
您可以看到結果始終是IO b
操作,因此嘗試更改任何 arguments 都無濟於事。
如果您想了解類型為何如此,您可以閱讀一些 monad 教程。 其背后的直覺是:不執行動作就無法執行動作。
在問題的實際方面,要使用某些操作返回的值,而不是嘗試use (extractValue inputAction)
,這沒有意義,因為extractValue
是不可能的,嘗試inputAction >>= use
如果您use
則使用涉及 I/O,如果不涉及,則fmap use inputAction
。
如果您希望它返回str
而不是()
,則應該在read'
中使用return str
。 您不能從read'
類型中刪除IO
,因為它不是純 function。 為了更好地了解 Haskell 中的輸入/輸出如何工作,我建議您閱讀教程。
作為更詳細的原因:它允許雜質。
您絕對不能在純操作期間執行 IO ,否則會完全破壞引用透明性。 從技術上講,您可以使用unsafePerformIO
,但在這種情況下它會破壞參照透明性——您應該只在可以保證結果始終相同的情況下使用它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.