本文的主要内容参考自Haskell 趣学指南
1. What is Haskell?
以下内容引用自 Haskell https://www.haskell.org/ 官网:
Haskell 是一个先进的, 纯粹的函数式编程语言. 一个典型的声明式地, 静态类型的代码如下:
- primes = filterPrime [2..]
- where filterPrime (p:xs) =
- p : filterPrime [x | x <- xs, x `mod` p /= 0]
Haskell 有如下的特性:
静态类型(Statically Typed).Haskell 的每一个表达式都有一个在编译时决定的类型. 所有的由函数引用组合起来的类型必须相匹配(match up), 否则无法正常编译. 类型不仅仅是形式上的保证, 更是用于表达程序结构的语言.
纯粹函数式(Purely functional).Haskell 的每一个函数都是数学意义上的(pure). 即使是有副作用的 IO 操作也不过是在描述在做什么, 同样由纯粹的代码产生. 没有声明或者指令, 仅仅只有表达式, 该表达式不能对变量进行修改(局部变量或者全局变量), 或者是获取像时间, 随机数这样的状态.
类型推断(Type Inference). 你并不需要在 Haskell 中显式地写出每一种类型, 类型将会进行双向推断. 当然, 你也可以选择自己写出类型, 或者让编译为你进行推断.
并发(Concurrent).Haskell 可以很容易进行并发编程, 这得力于它可以显式地处理 effects. 它的王牌编译器 GHC 带有一个高性能的并行的垃圾回收器, 还有一个轻量级的并发库, 其中包含了很多的有用的并发函数原型以及抽象接口.
惰性计算(Lazy). 函数并不会直接计算它们的值. 这意味着程序可以在一起组合地非常好, 可以通过只写通常的函数就表达控制结构(if/else).Haskell 代码的纯粹性使得它可以轻松将函数链式组合, 操作起来非常方便.
包(Packages). 你可以在 public packages server 上找到非常多的活跃的开源 Haskell packages.
2. How to use Haskell?
你可以下载 Haskell 的 GHC 编译器, 该编译器可以解释也可以编译 Haskell 程序. GHC 还有一个很有用的交互模式, 在终端输入 ghci 即可进入交互模式. 然后运行命令: l demo.hs 就可以加载 demo.hs 中的函数(Haskell 程序文件以 hs 结尾). 如果你对 demo.hs 做了修改, 可以重新运行命令: l demo.hs 以重新加载其中的函数. 这是我们以后实验学习 Haskell 的基本流程.
3. Basic Operations
3.1 基本类型
在终端输入 ghci 进行入交互模式. 如下是一些基本的运算, 几乎不用解释就可以看懂.
- Prelude> 2+15
- 17
- Prelude> 45*90
- 4050
- Prelude> 568-23
- 545
- Prelude> 3/2
- 1.5
- Prelude> (90-23)*8
- 536
- Prelude> 50*(100-9028)
- -446400
- Prelude> True && False
- False
- Prelude> True && True
- True
- Prelude> False || True
- True
- Prelude> not False
- True
- Prelude> not (True && True)
- False
- Prelude> 5 == 4
- False
- Prelude> 5 == 5
- True
- Prelude> "Hello" == "Hello"
- True
- Prelude> 5 /= 4
- True
- Prelude> 5 /= 5
- False
3.2 基础函数
3.2.1 Haskell 常用内置函数
succ.succ 函数返回一个数的后继. 比如:
Prelude> succ 10 11
注意 Haskell 中函数的调用参数是使用空格的, 这一点和传统的编译型语言有很大的不同.
pred.pred 函数和 succ 函数相反, 它返回一个数字的前驱. 比如:
Prelude> pred 10 9
min.min 函数接收两个数字参数, 返回这两个数字的最小值. 比如:
- Prelude> min 10 3.4
- 3.4
如果要比较多个数字的最小值, 直接传递多个数字作为参数会报错, 比如:
- Prelude> min 1 19 23
- <interactive>:21:1:
- Non type-variable argument in the constraint: Num (a -> t)
- (Use FlexibleContexts to permit this)
- When checking that 'it' has the inferred type
it :: forall a t. (Num a, Num (a -> t), Ord (a -> t)) => t
我们可以通过多次调用 min 函数 (注意需要加括号) 来解决:
- Prelude> min 1 (min 9 23)
- 1
max.max 函数返回两个数字的最大值. 比如:
- Prelude> max 9.9 9.0
- 9.9
Haskell 中函数拥有最高的优先级. 下面两句是等效的:
- Prelude> succ 10 + max 10 20 * 3
- 71
- Prelude> (succ 10) +(max 10 20)*3
- 71
注意 succ 9*10 的值是 100 而不是 91, 这是因为计算的顺序是先计算 succ 9 得到 10, 然后再计算 10*10=100, 如果我们要计算 9*10 的后继, 需要写成 succ (9*10)的形式.
div.div 函数计算一个整数除以另外一个整数的结果, 比如:
- Prelude> div 10 3
- 3
- Prelude> div 10 5
- 2
需要注意的是, div 函数接收的两个参数必须是整数, 第一个是被除数, 第二个是除数, 如果除不尽则返回商, 舍弃余数. 传入数字不能是浮点数, 比如下面的形式会报错:
- Prelude> div 1.2 3
- <interactive>:31:1:
- No instance for (Fractional a0) arising from a use of 'it'
- The type variable 'a0' is ambiguous
Note: there are several potential instances:
- instance Integral a => Fractional (GHC.Real.Ratio a)
- -- Defined in 'GHC.Real'
- instance Fractional Double -- Defined in 'GHC.Float'
- instance Fractional Float -- Defined in 'GHC.Float'
- In the first argument of 'print', namely 'it'
In a stmt of an interactive GHCi command: print it
3.2.2 构建自己的函数
doubleMe.doubleMe 函数的定义如下:
doubleMe x = x + x -- 将数字变为两倍
这个函数非常简单, 就是返回一个数字的两倍. 注意上面函数的定义方式: 首先是函数名字, 然后是空格分隔的参数, 接着是等于号, 等于号后面的是函数的实现. 要运行这个函数, 需要把它写在一个文件里, 比如 add.hs, 然后输入 ghci 进入命令行模式, 输入: l add.hs 就可以加载函数了. 下面是它的调用计算结果:
- Prelude> :l add.hs
- [1 of 1] Compiling Main ( add.hs, interpreted )
Ok, modules loaded: Main.
- *Main> doubleMe 2
- 4
- *Main> doubleMe 3
- 6
doubleUs. 该函数接收 x,y 两个参数, 然后返回这两个参数之和的两倍. 定义如下:
doubleUs x y = x*2 + y*2 -- 两个数字变为两倍然后相加
调用计算结果为:
- *Main> doubleUs 1 3
- 8
- *Main> doubleUs 0 2
- 4
useDoubleMe. 该函数功能和 doubleUs 一样, 只不过其调用了 doubleMe 两次, 代码如下:
useDoubleMe x y = doubleMe x + doubleMe y -- 调用简单函数
对了, 忘了说了, haskell 中注释是 --.
doubleSmallNumber. 该函数使用 if else 语句实现的功能是: 如果 x 小于 100 则返回 x; 否则返回 x 的两倍. 代码如下:
doubleSmallNumber x = if x <100 then x else 2*x -- 如果 x 小于 100 返回 x, 否则返回 2*x
调用结果为:
- *Main> doubleSmallNumber 20
- 20
- *Main> doubleSmallNumber 200
- 400
需要注意的是 Haskell 中 if 和 else 一定是一起出现的, else 不可以省略, 而且本质上 if 和 else 都是需要返回一个值. Haskell 中所有的函数和表达式都需要返回一个结果, if 语句就是一个表达式, 所以它一定会返回一个结果.
doubleSmallNumber'.doubleSmallNumber'函数 (注意函数最后有一个') 返回的结果是 doubleSmallNumber 返回值加 1, 定义为:
doubleSmallNumber' x = (if x <100 then x else 2*x) + 1 -- doubleSmallNumber 返回值加 1
我们通常在 Haskell 中在函数名字最后加一个'来表示对某个函数稍微修改之后得到的新函数. 上面的函数如果把括号去掉, 那么只会在 x>=100 的时候加 1 了. 另外需要注意的是, Haskell 的函数名字开头不能是大写字母.
conanO'Brien.conanO'Brien 是一个没有参数的函数, 这样的函数也被称为 "定义" 或者 "名字".conanO'Brien 定义如下:
conanO'Brien ="It's a-me, Conan O'Brien!" -- 没有参数的函数
上面的 conanO'Brien 函数定义好了之后, conanO'Brien 就与字符串
"It's a-me, Conan O'Brien!"
等价了, 而且字符串的值是不可以修改的.
haskell 简明入门(一)
来源: http://www.bubuko.com/infodetail-2619310.html