Haskell中的类型

Haskell中的类型

在Haskell中,每个表达式都会在编译时得到明确的类型,从而提高代码的安全性。当然这样就会导致在输入不同的类型进行某些操作时候得到编译捕获错误
这自然好过在运行时出现崩溃,然后自己去逐个排查是什么问题。Haskell中一切皆有类型,因此编译器在编译期间可以得到更多的消息来检查错误

ghci中可以使用:t命令,后接任何合法表达式查阅其类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ghci> :t 'a'
'a' :: Char

ghci> :t "a"
"a" :: String

ghci> :t True
True :: Bool

ghci> :t "Hello"
"Hello" :: String

ghci> :t (True,'a')
(True,'a') :: (Bool, Char)

ghci> :t 123
123 :: Num p => p

ghci> :t 5 == 3
5 == 3 :: Bool

有一个好习惯是在编写函数时,显示写出函数的类型

1
2
3
4
5
6
7
8
9
10
removeNonUpperCase :: [Char] -> [Char]
removeNonUpperCase st = [ c | c <- st, c `elem` ['A'..'Z']]

addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z

main = do
putStrLn "Trust type"
print (removeNonUpperCase "abcDEF")
print (addThree 1 2 3)

在这里 :: 读作“它的类型为”,凡是确定的类型,首字母一定是大写的。在这里removeNonUpperCase的类型是[Char] -> [Char]
也就是说接受一个[char]类型作为输入参数,返回一个[char]类型作为输出。在《Haskell趣学指南》中,可能是因为年代原因还有版本原因,字符串输出的
结果是[char]而在本人目前这个版本(GHCI 9.0.2) 字符串的类型已经是 String

String :: *

Defined in ‘GHC.Base’ (base-4.15.1.0)

A String is a list of characters. String constants in Haskell are values of type String .

See Data.List for operations on lists.*

Haskell中常见的类型

常见的基本类型用于表示数,字符,布尔值的类型

数字

  • Int: 整数类型, Int是有界的也可以称作是有符号类型,它的上下限取决于CPU。假设是64位的CPU,它的范围就是 -2^(64-1) ~ 2^(64-1)-1
  • Integer: 无符号整数类型, 可以存非常非常大的一个正整数,但是效率不如Int (详见计算机编码的内容)
  • Float: 单精度浮点类型
  • Double: 双精度浮点类型。精度是Float的两倍,这也意味着占用更大的空间。

字符和字符串

  • Char: 表示一个Unicode字符,一个字符由单引号括起
  • [Char]: 字符列表,可以当作字符串使用
  • String: 字符串类型

布尔类型:

  • Bool: 布尔类型,True和False

类型变量

有一些函数可能需要处理多个类型,或者说多个类型都需要用这个函数进行处理。如果用函数式编程的思想考虑,那么说一个函数的功能可以处理多个类型的参数,这
更为贴切一点。比如 head, tail, min, max他们都可以处理多种类型。好奇心一下子就上来了,那么这些函数的类型是什么呢?

1
2
3
4
5
6
7
8
ghci> :t head
head :: [a] -> a

ghci> :t min
min :: Ord a => a -> a -> a

ghci> :t tail
tail :: [a] -> [a]

我们知道大写开头的才是一个类型,那么这个必不是一个类型,这其实是个类型变量(type variable),也就会a可以是任何一个类型。作为一个C++老玩家,
这一刻觉得这个东西是真得强大,在类型安全的情况下可以简单实现处理多种类型的函数,容易写出通用的函数。

使用了类型变量的函数被称作多态函数(polymorphic function) 我们可以写一个简单的针对于数字的加法函数

1
2
3
4
5
plusTwoNumber :: Num a => a -> a -> a
plusTwoNumber x y = x + y

main = do
print (plusTwoNumber 1 2)

这里和C++的template模板以及auto比较一下(我个人还是非常喜欢C++的,现在新版的类型推导也是很好用,模板就有点小麻烦了)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//类型推导方式
auto sum(auto a, auto b) -> decltype(a + b){
return a + b;
}

//模板方式
template <typename T>
concept Number = std::is_integral_v<T> || std::is_abstract_v<T>;

template <Number T>
T sum(T a, T b) {
return a + b;
}


Haskell中的类型
http://cvrain.cloudvl.cn/2023/11/13/Haskell/haskell-type/
作者
ClaudeRainer
发布于
2023年11月13日
许可协议