Learn You a Haskell for Great Good!——(1)Haskell简介 - Daybreakcx's Blog - Keep Programming! With Algorithm! With Fun!
Learn You a Haskell for Great Good!——(2)起步

Learn You a Haskell for Great Good!——(1)Haskell简介

daybreakcx posted @ 2010年1月16日 19:51 in 学习笔记 , 3049 阅读

        最近看到了这个网站:learnyouahaskell.com/,相当于一个Haskell教程,内容很不错,插图很有意思,学习起来很快,因此最近就开始看这个资料,并留下一些学习笔记供以后回来复习之用。不得不说网上关于Haskell的资料不算太多(和C/C++那些比),但是好资料也不少,如《Real World Haskell》,《Programming in Haskell》还有《Yet Another Haskell Tutorial》等等,但是有些时候学习起来会有一定的难度,各个教材侧重点也都不同,之前也都大概浏览了一下,有了个大概的认识,现在就来看看这篇文章写得如何了,基本上的原则是看一章后写个总结,慢慢看,深入理解。

        Haskell是一种纯函数式编程语言,说它纯是因为他没有变量和副作用,没有变量这一点上,不同于以前学过的如C这类语言,C中可以很方便地进行内存操作,比如你显式地做一个变量声明操作,或者调用malloc这类函数进行内存的申请;同时也不同于如python这类语言,python中看似与C相似,实际上如果你仔细分析就会发现略有不同,在我看来,python更多的是C中的指针,比如我们进行如下操作: 

a=2
b=a
id(a)
id(b)
a=3
id(a)
id(b)

        进行这样的操作后在我的机子上的结果是: 

>>> a=2
>>> b=a
>>> id(a)
152635220
>>> id(b)
152635220
>>> a=3
>>> id(a)
152635208
>>> id(b)
152635220

        也就是说其中的赋值语句更类似于这种机制:先申请一块固定的内存,所有的变量赋值操作都实际上是地址的传递而非实际值的传递。更直接地说那些变量的操作都是指针操作,至于完全的值复制就需要调用特定的复制函数了。

        而Haskell里头是没有变量这一概念的,实际上从我这段时间的了解来看,Haskell所有的操作中的看似变量的部分都只是一个助记,不管你怎么定义,到了执行的时候都会被转换为其他的内容,可能是某个值,或者可能是某个表达式,也就是说完全都是表达式的叠代,其机理类似于C中的define,define操作的本质是编译器进行大量的字符串替换,而Haskell的机制是很类似的。正由于这个机制才使得其实现高阶(high order)函数非常方便。

        再说副作用,这个如何理解呢?在我们常规的编程语言中,特别是进行如多线程程序设计时候,有个元素是非常常见但是却常常困扰我们的,那就是环境,更细点说是例如全局变量这类的东西,全局变量的作用域是整个程序,有其好处当然也有其不利的一面,如果其读写是全局的,没有很好的设计就会成为一个很致命的bug,当然实现进程间通信不是只有利用全局变量这一招,还可以用共享内存,管道等等,但是其程序的执行始终都依赖着当前的某些量,而在Haskell中,无副作用则表现为一个函数的执行与环境无关,只与你传入的参数有关,其只负责返回由传入参数确定的结果。

        接下来再说Haskell的特性,Haskell是一种惰性(lazy)语言,什么意思呢?就是说除非明确指定,Haskell不会在必须向你展示结果之前实际执行或者计算,而平时只进行不停的叠代操作。这个性质看似无用,实际上其作用非常的大,一方面对于某些不必要的操作不予以计算浪费事件,另一方面这个特性还支持如无限数据结构这种东西。想过无限数据结构有什么用吗?有些时候我们在C中的for循环是不写终止条件的,因为你知道其一定会在某个时刻终止,而这个已经很贴近了。比如我们在Haskell中可以这样: 

Prelude> zip [1..] ["one","two","three","four","five","six"]
[(1,"one"),(2,"two"),(3,"three"),(4,"four"),(5,"five"),(6,"six")]

        zip的作用是将两个列表的对应元素作为tuple形成一个列表,而[1,,]则是一个以1开头的递增的无限列表。zip作为一个函数,如果在C这类语言中如此执行,由于执行之前要先进行参数值的计算后进行值传递,计算[1..]必然没有终结,但是实际上其只需要前六项就能得到结果,而Haskell则可以满足这种需求,由于其是惰性的,并不实际计算先[1..],直到其遇到其中一个列表结束才对他们进行打包的操作,我们的结果便得到了。其不存在先算哪个的问题,比如你可以这么试验: 

Prelude> zip3 [1..] ["one","two","three","four","five","six"] [2,4..]
[(1,"one",2),(2,"two",4),(3,"three",6),(4,"four",8),(5,"five",10),(6,"six",12)]

        Haskell还有一个特性是其是静态类型的,正因为如此其支持类型推断,怎么理解呢?首先在C这类语言中支持一个类型转换操作,有时候是显式的,有时候是隐式的,由于数据的存储上是无差别的,都是以二进制的形式存储,所以一直以来都这么用了,而且约定了相应的规则。而在Haskell中如果你想直接混用,编译器是不会让你如愿以偿的,除非通过某些函数进行相应的操作,否则数值是数值,字符串是字符串。正因为有如此严格的制度,Haskell才可以支持类型推断操作,也就是可以根据你传入参数的类型和你函数执行的操作推断出你的返回的类型,而也因此Haskell的编译过程显得特别的严格,曾听说社区里头的一句话说凡是编译通过的Haskell程序都是正确的,大概意思是这样,可见其编译过程是何等的严格,当然程序错误不单单是语法错误,还有逻辑错误等等,话语略显夸张,但是却很能说明问题。

        同时Haskell还是一种优雅与简洁的语言,之所以这么说是因为其对于高阶理念支持的很好,你可以将函数作为参数传入另一个函数,这就使得代码的重用性得意加强,而且更接近自然语言,你会发现Haskell的程序是非常美丽与可爱的。

        Haskell是由一群非常重名的家伙创造的,原文中也以kiss-ass一词来对她进行描述,你在Windows或者Linux下都可以书写Haskell程序,你只需要一个好的文本编辑器和一个好的编译器即可。现在流行的两种编译器是GHC和Hugs,安装都很方便。如果你是Linux用户,yum或者apt-get就可以了,而现在貌似用GHC的人更多点,同时大量的教材也是用的GHC。你可以通过两种模式来接触Haskell,一种是像那些动态脚本语言那样一条条命令地执行,利用ghci命令,你可以将其当做一个很好的计算器,其操作类似于python,很方便;同时你可以通过写好.hs文件然后像C程序那样编译,运行,总之你会玩得很开心的。

        至于ghci的命令,大家可以输入“:?”来进行查询,都很简单很方便,ghc的用法大家也可以man一下,用不了你太多的时间的。

        最后说一句:Have Fun!~~


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter