Haskell 趣学指南第九章:Input and Output

输入和输出

未完,待续~~~~~~~~~~~~(博客里的Markdown有点不如人意,请见谅)

前面已提到过Haskell是纯函数语言。在命令式语言中你可以指定一系列步骤让计算机去执行,然后得到结果,而函数语言则更偏向于定义它们。
在Haskell里,函数不能更改状态,例如改变变量的值(如果一个函数改变了状态,我们说它存在副作用)。
在Haskell里,函数只能做的事就是根据我们传给它的参数返回结果。如果给一个函数传递相同的参数,那么它应该始终返回相同的结果。
如果你习惯于命令式语言,刚开始这可能觉得被限制了,但很快你就能体会到其实这很酷。
在命令式语言中,即使是一个简单的函数,你也不能保证在处理数据时,它不会放火烧你的房子、绑架你的狗、用土豆刮伤你的汽车。(译注:这里是幽默的说法,意思是存在副作用)
举例说明,就是当我们创建二叉搜索树时,我们插入新元素时不能修改当前的树。
表面上,我们是插入新元素到当前二叉树中,但实际上却是我们创建了一棵新树,而不是修改当前树。

函数不能改变状态,看起来很酷,它能够让我们的程序更可靠。只是还有一个问题 ^-^,如果函数不能改变任何东西,那它怎么告诉我们计算结果?
为了告诉我们计算结果,它只能改变我们的输出设备(通常就是屏幕了^-^),设备发射光子到我们的眼睛,改变我们头脑的状态。^_^

不要绝望,还是有办法解决滴。实际上Haskell有一个聪明的脑袋,可以在函数中区分出存在副作用和纯净的部分。将存在副作用的代码与我们的程序分离出来,留下纯净的代码
与我们交互。存在副作用的场景可能是我们与键盘或屏幕的交互。
因为区分出了两部分,所以我们的程序还是很可靠的。与外界沟通时,我们的代码仍然具有惰性、鲁棒性、和模块化。

Hello, world!

在这之前,我们经常用GHCI来加载自己的函数并且玩得不亦乐乎。我们也探讨了一些标准库函数。
现在,经过了8个章节的学习后,我们将真正开始写第一个Haskell程序。耶!和平常一样,我们将以"hello, world"起头。

注意啦!在此章节里,我将假设你用的是*inux环境来学习Haskell。如果你使用的是Windows,我建议你下载Cygwin,它可以让你在Windows下 有类Linux的感觉。

现在,用你喜欢的文本编辑器敲下面的代码。

main = putStrLn "hello, world"

我们定义了一个main函数,它调用了putStrLn函数,参数为"hello, world"
看,就这么简单,一分钟都不到。保存文件为helloword.hs

现在,让我们做一些从未做过的事——真正的编译我们的代码。太让我兴奋了!
打开终端并导航到helloword.hs所在目录,敲下面命令:

$ ghc --make helloworld  
[1 of 1] Compiling Main             ( helloworld.hs, helloworld.o )  
Linking helloworld ...  

Okay!不出意外的话,你会看到结果。然后你就可用./helloword跑你的程序了。

$ ./helloworld  
hello, world  

到此结束,我们的第一个程序经过编译并在终端打印出了结果。这也太无聊了吧!

让我们回顾一下刚才到底写了什么。首先,看看函数putStrLn是什么类型。

ghci> :t putStrLn  
putStrLn :: String -> IO ()  
ghci> :t putStrLn "hello, world"  
putStrLn "hello, world" :: IO ()  

我们可像这么读putStrLn的类型:putStrLn取一字符串,返回一I/O 操作结果类型是()
(例如,空元组,也可以称为单元)。I/O 操作可以这么理解,将执行一个含有副作用的操作(通常是读取输入或者打印输出到屏幕)并以某种形式包含在返回值中。
打印字符串到终端并不是真正意义上的返回值,所以用虚拟的值()代替。

空元组的值为(),并且它的类型也是()

那么,I/O 操作到底什么时候被执行?答案是,当执行到main时。当我们执行到main函数时,就会执行I/O 操作。

在你的整个程序里,只能有一个I/O 操作看起来是一种限制。这就是为什么我们能用 do 语法将几个I/O 操作组合成一个的原因。看看下面的例子:

main = do  
    putStrLn "Hello, what's your name?"  
    name <- getLine  
    putStrLn ("Hey " ++ name ++ ", you rock!")  

啊哈,新语法,看起来很有趣!并且它看起来有点像命令式编程。编译并运行它,它的结果和你所想的可能完全一样。
注意,我们写 do 之后,列出了一系列的步骤——就像在命令式编程里一样。每一个步骤都是一 I/O 操作。
用 do 语法将它们组合成一个 I/O 操作。此操作的类型为 IO (),因为最后的I/O 操作就是这个类型。

正因如此,main函数经常有类型签名 main :: IO somethingsomething是具体的类型。
按照惯例,我们通常不直接声明 main的类型。

一切版权归原作者所有,但此译文版权公用。引用时如能保留译者leekelby, 将不甚感激!

Haskell本人初学乍到,如对翻译有任何批评或建议,欢迎留言或给我Email, leekelby AT gmail DOT com

转载于:https://my.oschina.net/kelby/blog/193136

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值