Alb*_*zia 4 io monads haskell do-notation io-monad
我正在从用户必须输入的输入中读取几行内容:
main :: IO ()
main = do
let size = 3
arr <- replicateM size getLine
let pairs = map parsePair arr
print pairs
Run Code Online (Sandbox Code Playgroud)
为什么我可以map parsePair arr在单独的行上做而不是在同一行上做,像这样:
arr <- map parsePair (replicateM size getLine)
Run Code Online (Sandbox Code Playgroud)
这样做,我得到了错误?:
• Couldn't match type ‘[]’ with ‘IO’
Expected type: IO [Int]
Actual type: [[Int]]
Run Code Online (Sandbox Code Playgroud)
为了给您更多细节,这里是parsePair:
parsePair string = map parseInt $ words string
parseInt :: String -> Int
parseInt s = read s :: Int
Run Code Online (Sandbox Code Playgroud)
由于replicateM size getLineis 的类型IO [String],因此不是Strings 的列表,因此它基本上是对IO将获得a 的动作的描述[String]。您可以<-在IOmonad中看到箭头,以检索它并解压缩结果。
然而,你可以做一些处理上,像,因为IO是一个Functor为好,你可以使用fmap :: Functor f => (a -> b) -> f a -> f b:
main :: IO [Int]
main = do
let size = 3
fmap (map parsePair) (replicateM size getLine)Run Code Online (Sandbox Code Playgroud)
或者,您可以将fmap移至该getLine零件:
main :: IO [Int]
main = do
let size = 3
replicateM size (fmap parsePair getLine)Run Code Online (Sandbox Code Playgroud)
请注意,readLn :: Read a => IO a基本上有一个函数fmap read getLine(除了它会执行一些其他错误处理)。因此,我们可以使用:
main :: IO [Int]
main = do
let size = 3
replicateM size readLnRun Code Online (Sandbox Code Playgroud)
请注意,do带<-符号的语法实际上不像赋值运算符(这=在许多语言中,有时:=甚至有时<-在R中)。相反,它是一种特殊的结构,可执行单子动作并提取该动作的结果。行动与其结果之间存在根本区别;并且经常被引用的比喻是,动作就像蛋糕的配方,结果就是蛋糕本身。
申请map parsePair直接到IO行动会像服用用刀凌迟配方,并期望你就可以使用该配方烤准备切割的蛋糕。显然,这不是它的工作原理。
同样,您首先需要执行(绑定)IO动作,然后才能操纵结果。这就是在线上发生的事情arr <- replicateM size getLine:执行该动作,并且仅将其结果存储在其中arr,以便您可以编写map parsePair arr。
或者,您可以使用fmap运算符。这基本上是做的,它需要一个配方和一些指令来处理结果,然后将该指令添加到配方的末尾。如果您随后执行该配方,则其结果的确将蛋糕切成薄片。
| 归档时间: |
|
| 查看次数: |
81 次 |
| 最近记录: |