接受函數getLine。從IO a - > a寫一個函數?
它有一個類型
getLine :: IO String
我如何提取此IO值的字符串。更一般地說,我該如何轉換它。
IO a
這樣:
a
如果這是不可能的。爲什麼我不能這樣做?
接受函數getLine。從IO a - > a寫一個函數?
它有一個類型
getLine :: IO String
我如何提取此IO值的字符串。更一般地說,我該如何轉換它。
IO a
這樣:
a
如果這是不可能的。爲什麼我不能這樣做?
在Haskell中,當您想使用IO
中的「被困」值時,您不會從IO
中獲取值。相反,您也可以將要執行的操作也放入IO
!
例如,假設您想要使用Prelude中的length
函數來檢查getLine :: IO String
將產生多少個字符。
存在着所謂的fmap
一個輔助功能,當專用於IO
,有類型:
fmap :: (a -> b) -> IO a -> IO b
它需要的是在不陷入IO
「純粹」價值工程的功能,併爲您提供了一個功能它與陷於IO
的值一起工作。這意味着代碼
fmap length getLine :: IO Int
表示IO
的行動,讀取控制檯線,然後給你它的長度。
<$>
是fmap
的infix的同義詞,它可以使事情變得更簡單。這相當於上面的代碼:
length <$> getLine
現在,有時操作要與IO
-trapped價值本身返回IO
-trapped值執行。簡單的例子:你要使用putStrLn :: String -> IO()
來回寫你剛剛閱讀的字符串。在這種情況下,fmap
是不夠的。您需要使用(>>=)
運營商,該運營商專用於IO
時,其類型爲IO a -> (a -> IO b) -> IO b
。在出情況:
getLine >>= putStrLn :: IO()
使用(>>=)
到鏈IO
行動有必要的,連續的味道。有一種叫"do-notation"語法糖,這有助於寫在一個更自然的方式這樣的順序操作:
do line <- getLine
putStrLn line
請注意,這裏的<-
不是運營商,而是由DO提供的語法糖的一部分符號。
這個常見問題的簡單解釋! 「相反,你把你想要執行的操作也放到IO中!」 – luqui
如果你知道C然後考慮問題「我怎麼能從gets
得到字符串?」一個IO String
不是一些很難得到的字符串,它是一個可以返回字符串的過程 - 就像從網絡或標準輸入讀取一樣。你要運行程序獲取一個字符串。
在一個順序運行IO操作的常用方式是do
符號:
main = do
someString <- getLine
-- someString :: String
print someString
在上面運行getLine
操作獲得String
值,那麼無論你希望使用的值。
如果您處於do
塊中,則不會涉及任何細節,您可以(非正式/不正確)將<-
視爲從IO中獲取值。
例如,下面的函數需要從getLine
線,並將它傳遞給純函數,只需要一個String
main = do
line <- getLine
putStrLn (wrap line)
wrap :: String -> String
wrap line = "'" ++ line ++ "'"
如果編譯以此爲wrap
,並在命令行運行
echo "Hello" | wrap
你應該看到
'Hello'
所以「一般」,目前還不清楚爲什麼你認爲你需要這種類型的功能,在這種情況下,它使所有的差異。
爲了完整性,應該注意的是它是可能的。確實存在名爲unsafePerformIO
的基礎庫中的類型爲IO a -> a
的函數。
但unsafe
部分是有原因的。有很少的情況下,其使用被認爲是合理的。這是一個逃生艙,要謹慎使用 - 大多數時候你會讓怪物進來而不是讓自己出去。
爲什麼你不能從IO a
到a
?那麼至少它可以讓你通過看似純粹的功能來打破規則 - 哎!如果這是一種常見做法,那麼類型簽名和編譯器爲驗證它們所做的所有工作根本沒有意義。所有的正確性保證將會離開窗口。
哈斯克爾部分地是有趣的,正是因爲這是(通常)不可能的。
對於如何處理您的問題getLine
特別看到其他答案。
因爲如果你可以做到這一點,首先要有一個IO類型沒有意義。 – sepp2k
可能會重複:[*我如何解析在Haskell中的IO字符串?](http://stackoverflow.com/q/11229854/2751851)(我沒有自己關閉它,因爲它可能會使更好重複的目標)。 – duplode