[英]What is the IO type in Haskell
我是 Haskell 編程語言的新手,我一直在IO
類型上絆倒,無論是作為 function 參數還是返回類型。
playGame :: Screen -> IO ()
或者
gameRunner :: IO String -> (String -> IO ()) -> Screen -> IO ()
這是如何工作的,我有點困惑,因為我知道 String 需要單詞而 Int 需要數字。 函數期望或返回中使用的IO
是什么?
IO
是 Haskell 如何區分引用透明代碼和不透明代碼的方式。 IO a
是返回a
的 IO 操作的類型。
您可以將 IO 操作視為一段對等待執行的現實世界有一定影響的代碼。 由於這種副作用,IO 操作不是引用透明的; 因此,執行順序很重要。 正確排序和執行所有 IO 動作是 Haskell 程序的main
function 的任務。 因此,當您編寫返回IO a
的 function 時,您實際上正在做的是編寫 function 執行最終返回的動作 - 當由main
執行並返回a
動作時。
更多解釋:
引用透明性意味着您可以將 function 替換為其值。 一個參照透明的 function 不會有任何副作用; 特別是,引用透明的 function 無法訪問任何硬件資源,如文件、網絡或鍵盤,因為 function 值將取決於其參數以外的其他內容。
像 Haskell 這樣的函數式語言中的引用透明函數就像數學函數(域和余域之間的映射),而不僅僅是關於如何計算函數值的命令式指令序列。 Therefore, Haskell code says the compiler that a function is applied to its arguments, but it does not say that a function is called and thus actually computed.
因此,引用透明函數並不意味着執行順序。 Haskell 編譯器可以自由地以它認為合適的任何方式評估函數 - 或者如果沒有必要則根本不評估它們(稱為惰性評估)。 唯一的排序來自數據依賴性,當一個 function 需要另一個 function 的 output 作為輸入時。
現實世界的副作用不是引用透明的。 您可以將現實世界視為某種隱含的全局 state ,有效函數會發生變異。 由於這個 state,執行順序很重要:如果您首先從數據庫中讀取然后更新它會有所不同,反之亦然。
Haskell 是一種純函數式語言,它的所有函數都是引用透明的,編譯依賴於此保證。 那么,我們如何處理有效的函數,這些函數操縱一些全局真實世界 state 並且需要按特定順序執行? 通過在這些函數之間引入數據依賴性。
This is exactly what IO does: Under the hood, the IO type wraps an effectful function together with a dummy state paramter. 每個 IO 操作都將此虛擬 state 作為輸入,並將其作為 output 提供。 Passing this dummy state parameter from one IO action to the next creates a data dependency and thus tells the Haskell compiler how to properly sequence all the IO actions.
您看不到虛擬 state 參數,因為它隱藏在一些語法糖后面: main
和其他 IO 操作中的do
表示法,以及IO
類型內部。
簡單地說:
f1 :: A -> B -> C
是一個 function ,它采用A
和B
類型的兩個 arguments 並返回一個C
。 它不執行任何 IO。
f2 :: A -> B -> IO C
與f1
類似,但也可以執行 IO。
f3 :: (A -> B) -> IO C
將 function A -> B
(不執行 IO)作為參數並生成C
,可能執行 IO。
f4 :: (A -> IO B) -> IO C
takes as an argument a function A -> IO B
(which can perform IO) and produces a C
, possibly performing IO.
f5 :: A -> IO B -> IO C
takes as an argument a value of type A
, an IO action of type IO B
, and returns a value of type C
, possibly performing IO (eg by running the IO action argument one or more times).
例子:
f6 :: IO Int -> IO Int
f6 action = do
x1 <- action
x2 <- action
putStrLn "hello!"
x3 <- action
return (x1+x2+x3)
當 function 返回IO ()
時,它沒有返回有用的值,但可以執行 IO。 類似於在 C 或 Java 中返回void
。 您的
gameRunner :: IO String -> (String -> IO ()) -> Screen -> IO ()
function 可以用下面的 arguments 調用:
arg1 :: IO String
arg1 = do
putStrLn "hello"
s <- readLine
return ("here: " ++ s)
arg2 :: String -> IO ()
arg2 str = do
putStrLn "hello"
putStrLn str
putStrLn "hello again"
arg3 :: Screen
arg3 = ... -- I don't know what's a Screen in your context
讓我們先嘗試回答一些簡單的問題:
Haskell 中的Maybe
類型是什么?
來自Haskell 2010 報告的第 21 章(第 205 頁):
data Maybe a = Nothing | Just a
這是一個簡單的部分類型 - 你有一個值(通過Just
傳達)或者你沒有( Nothing
)。
這是如何運作的?
讓我們看一下Maybe
的一個可能的Monad
實例:
instance Monad Maybe where return = Just Just x >>= k = kx Nothing >>= _ = Nothing
這個 monadic 接口簡化了基於Maybe
構造函數的值的使用,例如,而不是:
\f ox oy -> case ox of Nothing -> Nothing Just x -> case oy of Nothing -> Nothing Just y -> Just (fxy)
你可以簡單地寫這個:
\f ox oy -> ox >>= \x -> oy >>= \y -> return (fxy)
monadic 接口應用廣泛:從解析到封裝 state 等等。
函數中使用的Maybe
類型期望或返回什么?
對於 function 期望基於Maybe
的值,例如:
maybe:: b -> (a -> b) -> Maybe a -> b maybe _ f (Just x) = fx maybe d _ Nothing = d
如果它的內容在 function 中使用,那么 function 可能不得不處理沒有接收到它可以使用的值,即Nothing
。
對於 function 返回基於Maybe
的值,例如:
invert:: Double -> Maybe Double invert 0.0 = Nothing invert d = Just (1/d)
它只需要使用適當的構造函數。
最后一點:觀察如何使用基於Maybe
的值 - 從簡單開始(例如invert 0.5
或Just "here"
)然后定義其他可能更精細的基於Maybe
的值(使用(>>=)
, (>>)
等)最終通過模式匹配直接檢查,或通過適當的定義抽象地檢查( maybe
, fromJust
等人)。
原始問題的時間:
Haskell 中的IO
類型是什么?
來自報告的第 6.1.7 節(第 75 頁):
IO
類型用作與外界交互的操作(動作)的標記。IO
類型是抽象的:沒有構造函數對用戶可見。IO
是Monad
和Functor
類的一個實例。
關鍵是:
IO
類型是抽象的:沒有構造函數對用戶可見。
沒有構造函數? 這就引出了下一個問題:
這是如何運作的?
這就是單子接口的多功能性所在:它的兩個關鍵操作符的靈活性——Haskell 中的return
和(>>=)
——基本上彌補了基於IO
的抽象值。
還記得關於如何使用基於Maybe
的值的觀察嗎? 那么,基於IO
的值以類似的方式使用 - 簡單地開始(例如return 1
, getChar
或putStrLn "Hello, there!"
)定義其他基於IO
的值(使用(>>=)
, (>>)
, catch
等)最終形成Main.main
。
但不是模式匹配或調用另一個 function 來提取其內容, Main.main
直接由 Haskell 實現處理。
函數中使用的IO
期望或返回什么?
對於 function 期望基於IO
的值,例如:
echo:: IO () echo:: getChar >>= \c -> if c == '\n' then return () else putChar c >> echo
如果它的內容在 function 中使用,那么 function 通常會返回基於IO
的值。
對於 function 返回基於IO
的值,例如:
newLine:: IO () newLine = putChar '\n'
它只需要使用適當的定義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.