haskell io中的中间值

时间:2014-07-03 08:30:04

标签: haskell io

我正在学习Haskell,作为练习,我编写了一个读取整数并打印下一个整数的程序:

main = do
    line_with_n_in_it <- getLine
    putStrLn $ show $ (read line_with_n_in_it :: Int) + 1

然而,对我而言,我必须明确指出我读过的那一行似乎很傻。

如果我写

main = do
    putStrLn $ show $ (read getLine :: Int) + 1

runghc抱怨read期望StringgetLine提供IO String。因此,根据我的理解,似乎这个神奇的<-运算符会将IO String转换为String

是否有一个不同的运算符或函数可以让我简单地内联<-运算符?因此,如果magic是我的神奇功能,我将能够将我的新程序编写为

main = do
    putStrLn $ show $ (read $ magic getLine :: Int) + 1

2 个答案:

答案 0 :(得分:4)

你应该阅读monads(和IO monad)

一个好的开始here

问题是你必须从monad中“提取”这个值,这不是“完全”的函数调用。

您的第一个代码是正确的,您从monad中提取了一些值

readedString <- getLine

然后,使用它

putStrLn $ "Readed: " ++ readedString

你可以避免“命名行”,但一般来说,这是一个很好的写名。

为了避免命名,你必须编写一些monadic函数然后绑定

getLine >>= putStrLn . show . (+1) . read

但是,我再次建议您阅读monads(和IO monad)。

顺便说一句,<-运算符“等于”>>=运算符,详情为here

答案 1 :(得分:1)

Haskell显然不允许这种行为的事实正是使它如此有价值的事实 - 你不能混合使用纯粹的和IO混乱的代码。

神奇的<-运算符是monadic绑定的语法糖。例如,您的原始函数可以使用>>=运算符(发音为“bind”)显式重写:

main = do
  n <- getLine
  putStrLn $ show $ (read n :: Int) + 1

===

main = getLine >>= \n -> putStrLn $ show $ (read n :: Int) + 1

<-对你来说似乎是神奇的事实是一件好事 - 它不是标准的haskell语法,它是糖。后一种编写函数的方式应该更有意义。

至于为什么这个有用,我可以给你一个特定于IO monad的手写解释,并建议你阅读Learn You a Haskell for Great Good!关于monad(或整本书)的章节,如果你真的是新的!)以加强你的理解。

我们走了。 getLineString读取IO,对吗?但这意味着调用的结果是“用IO标记”;它是String包裹在IO上下文中,我们无法操纵,因为我们可以正常String。执行此类操作会违反referential transparency,因为IO上下文(即您正在阅读的内容)可能会发生变化。基本上,魔术<-运算符所做的就是从String上下文“拉出”纯IO值并允许您对其进行操作。更明确地,>>=运算符执行IO操作(getLine),以及将String转换为新IO操作的函数(lambda表达式)在已翻译的示例中),并返回新的IO操作。这是一种将IO表达式链接在一起,并“挖掘”其内在值,对其进行操作,并在IO中重新包装它们的方法。 Monads一般不是我(或任何人)可以在SO答案中详细解释给你的,但我强烈建议你读LYAH,如果你打算继续学习Haskell - 这是一本好书并且会让你快速上手。