企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] ## Hindley-Milner 类型签名 - 类型(type)是让所有不同背景的人都能高效沟通的元语言 - 类型签名还衍生出了 “自由定理(free theorems)” 的概念 - 因为类型是可以推断的,所以明确的类型签名并不是必要的 - 类型签名不但可以用于编译时检测(compile time checks),还是最好的文档 ## 类型签名实例 实例1 ``` // match :: Regex -> (String -> [String]) var match = curry(function(reg, s){ return s.match(reg); }); // onHoliday :: String -> [String] var onHoliday = match(/holiday/ig); ``` - 函数都写成类似 a -> b 这个样子,其中 a 和b 是任意类型的变量 - 因此,capitalize 函数的类型签名可以理解为“一个接受 String 返回 String 的函数” - 每传一个参数,就会弹出类型签名最前面的那个类型 实例2 ``` // id :: a -> a var id = function(x){ return x; } ``` - `a->a` 表示从任意类型转到任意类型,但是类型是同一类型 实例3 ``` // map :: (a -> b) -> [a] -> [b] var map = curry(function(f, xs){ return xs.map(f); }); ``` - b 可能与 a 类型相同,也可能不相同 - 签名说明:map 接受两个参数,第一个是**函数**(从任意类型 a 到任意类型 b 的函数);第二个是一个**数组**,元素是任意类型的 a;map 最后返回的是一个类型 b 的**数组** ## 缩小可能性范围 一旦引入一个类型变量,就会出现一个奇怪的特性叫做*parametricity*,。这个特性表明,函数将会*以一种统一的行为作用于所有的类型* ``` // reverse :: [a] -> [a] ``` 意看`head`,可以看到它接受`[a]`返回`a`。我们除了知道参数是个`数组`,其他的一概不知;所以函数的功能就只限于操作这个数组上 类型`a`的多态性(polymorphism)都会大幅缩小`reverse`函数可能的行为的范围 ## 自由定理 ``` // head :: [a] -> a compose(f, head) == compose(head, map(f)); // filter :: (a -> Bool) -> [a] -> [a] compose(map(f), filter(compose(p, f))) == compose(filter(p), map(f)); ``` 第一个例子中,等式左边说的是,先获取数组的`头部`(译者注:即第一个元素),然后对它调用函数`f`;等式右边说的是,先对数组中的每一个元素调用`f`,然后再取其返回结果的`头部`。这两个表达式的作用是相等的,但是前者要快得多 ## 类型约束 签名也可以把类型约束为一个特定的接口(interface) ``` // sort :: Ord a => [a] -> [a] ``` 胖箭头左边表明的是这样一个事实:a 一定是个 Ord 对象。也就是说,a 必须要实现 Ord 接口。Ord 到底是什么?它是从哪来的?在一门强类型语言中,它可能就是一个自定义的接口,能够让不同的值排序