类型#

类型声明#

<name>, ... :: <type>
  • :::声明变量类型;

  • 同一类型的数据必定具有相同操作;

  • 可同时声明多个变量,不同变量用逗号分隔;

  • Haskell 为强静态类型语言,一切皆有类型,因此必须声明变量的类型,提高代码的安全性;

  • Haskell 支持类型推断,因此无需声明所有变量;

  • GHCi 中,:type:t可查看表达式类型;

    Prelude> :type 'a'
    'a' :: Char
    Prelude> :type True
    True :: Bool
    Prelude> :t 4 == 5
    4 == 5 :: Bool
    Prelude> :t "Hello!"
    "Hello!" :: [Char]
    

变量声明#

<name> = <value>
  • =
    • 声明变量的值为value
    • Haskell 中,=表示定义,而非赋值
  • 命名:
    • 大小写拉丁字母、数字、下划线以及单引号'为合法字符,但只能以小写字母或下划线开头;
    • Haskell 通常使用驼峰命名法;
  • 变量一旦声明,在同一程序内便不能更改,否则报错;
  • 在 Haskell 中,变量不是储存数据的容器,变量只是数据的别名
test.hs#
1x :: Int  -- x 有类型 Int
2x = 3     -- x **默认** 为 3
3x = 4
4-- test.hs:3:1: error:
5--     Multiple declarations of ‘x’
6--      Declared at: test.hs:2:1
7--                   test.hs:3:1

基本数据类型#

  • Int:整数,最值取决于 CPU 架构,在 64 位系统上,Int的取值范围为\(\pm2^{63}\)

    biggestInt, smallestInt :: Int
    biggestInt = maxBound  -- 该机器上的最大整数
    smallestInt = minBound -- 该机器上的最小整数
    
  • Integer:整数,最值取决于计算机内存容量;

    reallyBig :: Integer
    reallyBig = 2 ^ (2 ^ (2 ^ (2 ^ 2)))
    
  • Float:单精度浮点数,用 32 位来表示;

    f1, f2 :: Float
    f1 = 4.584234
    f2 = 6.2831e-30
    
  • Double:双精度浮点数,用 64 位来表示;

    d1, d2 :: Double
    d1 = 4.584234234230943
    d2 = 6.2831e-300
    
  • Bool:布尔值,只有TrueFalse两种;

    b1, b2 :: Bool
    b1 = True
    b2 = False
    
  • Char:单个 Unicode 字符,由单引号包围;

    c1, c2 :: Char
    c1 = 'x'
    c2 = '棒'
    
  • String:字符串,由双引号包围,其实质是一组字符列表;

    s :: String
    s = "Hello, Haskell!"
    

类型注释#

<object> :: <type>
  • 类型注释:对对象类型的注释,指定对象的类型;
  • 类型注释不一定出现在一行的末尾,可以通过括号改变类型注释的优先级;
exp1 = read "2" -- *** Exception: Prelude.read: no parse
exp2 = read "2" :: Int        -- 2
exp3 = read "2" :: Float      -- 2.0
exp4 = succ (read "2" :: Int) -- 3

类型变量#

  • 类型变量:表示任意类型,即该表达式类型无关;

    备注

    类型变量与其他语言中的泛型函数类似,但更强大。

  • 多态函数:使用了类型变量的函数;

  • 多态常量:使用了类型变量且仅声明了一个类型的变量;

  • 命名:

    • Haskell 允许类型变量为多字符,但约定俗成以单个小写字母表示;

      head :: [a] -> a
      -- 函数 'head' 取出并返回列表的第一个元素,列表元素可为任意类型
      
    • 不同字符不一定代表不同类型;

      fst :: (a, b) -> a
      -- 'a' 和 'b' 为不同的类型变量,但两者的类型不一定不同
      -- 这里仅表示返回值的类型与数对中的第一个元素类型相同
      

类型类#

(<typeClass> <typeVariable>, ...) => <typeVariable> -> ...
  • 类型类

    • 用于约束类型的接口;
    • 一种类型可以是多个类型类的成员,一个类型类也可以有多个类型成员;
  • 语法格式:

    • 类型约束:
      • 使用小括号()包围,在此约束类型;
      • <typeClass> <typeVariable>表示类型变量<typeVariable>为类型类<typeClass>的成员;
      • 多个类型约束用逗号,分隔;
      • 当只有一个类型约束时,括号可省略;
    • =>:定义类型约束,分隔类型约束和类型变量;
    • 类型变量:语法与函数定义相同;
    (==) :: Eq a => a -> a -> Bool
    -- '(==)' 接受两个任意类型的参数并返回布尔值
    -- 类型变量 'a' 属于 'Eq' 类型类
    

常用类型类#

  • Eq:可判断相等性(==/=),凡可比较相等性的类型都属于此类;

    elem :: (Foldable t, Eq a) => a -> t a -> Bool
    -- 若参数存在于列表中,则函数 'elem' 返回 'True'(成员判断)
    -- 该函数使用 '(==)' 和 '(/=)' 进行判断
    
  • Ord:可比较大小;

    • 除函数外,前文中的所有类型都属于此类;
    • Ord类型类的成员也必须是Eq的成员;
    compare :: Ord a => a -> a -> Ordering
    -- 函数 'compare' 比较两个参数,并返回表示两者关系的字符串
    -- 'GT'(大于),'EQ'(等于),或 'LT'(小于)
    -- 比较的参数属于 'Ord' 类型类
    
  • Show:可用字符串表示,除函数外的所有类型都属于此类;

    show :: Show a => a -> String
    
  • Read:可将字符串转为Read的某个成员;

    read :: Read a => String -> a
    
  • Enum:可枚举,有()BoolCharOrderingIntIntegerFloatDouble,该类型的值具有后继值和前趋值;

    enumFromTo :: Enum a => a -> a -> [a]
    
  • Bounded:具有上限和下限;

    minBound :: Bounded a => a -- 多态常量
    
  • Num:具有数字属性,所有数字都是多态常量;

    (*) :: Num a => a -> a -> a
    
  • Integral:整数数字,包含成员IntInteger

    fromIntegral :: (Integral a, Num b) => a -> b
    
  • Floating:浮点数数字,包含成员FloatDouble

    cos :: Floating a => a -> a
    
  • Foldable:可折叠类型,可理解为可迭代序列,Foldable t => t a表示数据为可折叠类型t,该数据下的元素类型为a

    foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b