Haskell 学习总结

2018/05/26 Haskell

知识点

GHCi

启动 GHCi, 在 Mac OS 上可以使用 stack 工具: stack ghci

-- Haskell 的源码文件使用 .hs 后缀,内容全部是源码
-- Literate Haskell 的源文件使用 .lhs 后缀,>开头后接一个空格的才算源码
-- 加载源码文件到 GHCi
:load file.hs
:l file.hs
-- 重新加载有修改的源码文件到 GHCi
:reload file.hs
:r file.hs
-- 执行多行语句
:{
let addTwo :: Int -> Int -> Int
    addTwo x y = x + y 
:}
-- 查看类型
:type 1
:t 1

基础语法

-- 单行注释使用 -- 开头
{-
    注释块使用 {--}
-}
-- 源文件中声明
x = 5     -- x is 5
answer = 2 * {-
    block comment
-} 3 {- inline comment -}
r = 5.0
-- GHCi 中声明变量
let r = 5.0
-- 分支语法
mySignum x = if x < 0 then -1 else 1
-- case of 语法
ex03 = case "Hello" of
    [] -> 3
    ('H':s) -> length s
    _ -> 7

函数

函数即是给定参数然后返回结果的东西,Haskell 中函数如下示例:

-- 函数名 参数列表 = 函数体
area r = pi * r ^ 2
-- 使用,参数实际值使用空格分割
area 5
-- 多参函数
areaRect l w = l * w
-- 函数组合
areaSquare s = areaRect s s
-- 模式匹配,调用时从上往下匹配到则直接返回
sumtorial :: Integer -> Integer
sumtorial 0 = 0
sumtorial n = n + sumtorial (n-1)
-- Guards 模式
absolute x
    | x < 0 = 0 - x -- 注意 - 也是一个函数, 必须使用两个参数
    | otherwise = x -- otherwise 始终是 True
-- 模式匹配和 Guards 模式可以一起使用
foo :: Integer -> Integer
foo 0 = 16
foo 1 
  | "Haskell" > "C++" = 3
  | otherwise         = 4
foo n
  | n < 0            = 0
  | n `mod` 17 == 2  = -43
  | otherwise        = n + 3
-- where 绑定变量
heron a b c = sqrt (s * (s - a) * (s - b) * (s - c))
    where s = (a + b + c) / 2
-- let in 绑定变量
roots a b c =
    let sdisc = sqrt (b * b - 4 * a * c)
        twice_a = 2 * a
    in ((-b + sdisc) / twice_a, (-b - sdisc) / twice_a)
-- where 和 Guards 组合到一起
numOfRealSolution a b c
    | disc > 0 = 2
    | disc == 0 = 1
    | otherwise = 0
        where
        disc = b ^ 2 - 4 * a * c
-- 函数的优先级始终比中缀操作符高
-- 会被识别为 (f 3 n) + (1 7)
f 3 n+1 7
-- 多参函数可以看做接收一个参数,返回一个函数
sum a b = a + b
addOne = sum 1

类型

Haskell 中所有类型都是以大写字母开头,所有变量都有类型。

Prelude> :t 'H'
'H' :: Char
Prelude> :t "Hello"
"Hello" :: [Char]

函数也有自己的类型,如下表示接收一个 Bool 然后返回一个 Bool

Prelude> :t not
not :: Bool -> Bool

定义函数时可以先声明其类型,不声明的话编译器会自动推断其类型:

xor :: Bool -> Bool -> Bool
xor p q = (p || q) && not (p && q)

常用类型:

类型 含义
Int 整数,有限
Integer 整型,无限
Double 浮点数
Bool 布尔值
(Type1,Type2…) 元组,Type1 Type2 是具体的类型,可以不同
[Type] 列表,Type 是具体的类型
Char 单个字符,值使用 ‘’ 括起来
String 字符串,[Char]的别名,使用 “” 括起来

类型定义使用 data 关键字,枚举列出类型所有的构造子,构造子像函数样被调用后会创建类型的值

data FailableDouble = Failure
            | OK Double
    deriving Show

-- 使用构造子创建类型的值
ex01 = Failure
ex02 = Ok 3.4
-- 使用构造子模式匹配
failureToZero :: FailableDouble -> Double
failureToZero Failure = 0
failureToZero (OK d) = d
-- 模式匹配的可选格式
-- pat ::= _
--     | var
--     | var@(pat)
--     | (cONSTRUCTOR pat1 pat2 ... path)
-- 类型定义可以使用递归, 也就是构造子参数中使用本类型
data IntList = Empty | Cons Int IntList
-- 使用泛型定义类型
data List t = E | C t (List t)

类型类

类型类类似于 Java 中的接口,他声明了一系列函数,类型可以实现这些函数,这样就可以将实际类型的值传给这些函数以实现类似泛型的功能。

比如 (+) 函数实际支持的就是 Num 类型类:

Prelude> :t (+)
(+) :: Num a => a -> a -> a
-- 1 是一个 Num, 但是他的具体类型会在用到的时候才确定
Prelude> :type 1
1 :: Num p => p
Prelude>  1 + 1
2
Prelude> :type 1.1
-- Fractional 是 Num 的子类型类
1.1 :: Fractional p => p
Prelude> 1.1 + 1.1
2.2
-- 1 是一个 Num,而 1.1 是一个 Fractional
-- 编译器会首先推断出 1.1 是一个 Double 类型(Fractional 下的类型)
-- 然后 1 也会被推断成 Double
Prelude> 1 + 1.1
2.1

Search

    Table of Contents