欢迎光临散文网 会员登陆 & 注册

结。 / 匹配子 —— Ruby 的类型论,实现参数多态和交换律、结合律(三)

2023-06-16 14:57 作者:花角  | 我要投稿

这是一个了断,

在写完这篇 匹配子 理论之后,

我不会再去学习和消费 数学游戏 了。

函数多态方式

类似 f :: a, b, c, d, e -> e 这种的

或者 f(a, b, c, d)

f :: a, b, c, d, e -> e 应当看成一个整体,也就是一个序列。

(a, b, c, d)输入序列-> e返回序列

为了不混淆,也就可以叫 serie(系列)

而函数的类型,等价于匹配序列的一个模式表达式。

函数类型 (int, int, int) -> int 匹配 (1, 2, 3)

-> int需要匹配调用它的函数的 槽位 的参数类型。

可以看到,类型——匹配子的对应关系如下:

设:

其中:

- 可以展开成一个树,被调用的函数称作某函数的上游函数,调用函数的函数称作某函数的下游函数

  • a() 有调用它的函数f()a()称作f()上游函数,而f()称作a()下游函数

  •  g() 没有调用者,故,g()称作该函数链的 根函数最终下游函数

  •  a() 没有上游函数,故,a()称作该函数链的 顶流函数,或末函数。

  •  f() 既有上游又有下游,称 介函数间函数

- 在 f(...) 中:

  - 第一个 a() 匹配下游调用 f() 的第一个槽位,f() 需要返回值为 int 类型的参数。于是 a() 调用了 (->int) 的分支函数

  - f() 的第二个参数槽位 需要 str 类型的参数,于是 a() 调用了 (->str)

- 在 g(...) 中:

  - g() 需要 int 类参数,于是 f() 调用 了返回值为 int 的分支函数


- 对于a()

  - 第一个a() 匹配下游f()的第一个槽位(int),f() 需要 int 类的参数,因此,a 调用了(->int) 的分支函数

  - 第二个a() 匹配 f() 的第二槽(str)。因此调用了(->str) 分支函数。

- 对于g()

  - 他需要一个 int 类的参数,返回 int 类的值

- 对于f()

  - 他在 g() 的第一个槽位,需要 int 类参数,因此,f() 确定了返回值类型,(...->int)

  - (...->)(int str->...) 组合一起,就确定了要调用 (int str -> int) 分支函数。

更复杂的情况:

展开成树后是:


此时,f() 返回值重载和他的下游函数 g() 该槽位的参数重载同时存在。

a()f() 互有重载冲突。

根本无法确定匹配哪个分支函数。

此时,为了确保只有一个结果——函数类型的确定性,可采取如下 解叠加消叠加态) 规则:

  1. 函数链 *全匹配* 原则:将函数链展开成树,对所有函数采取完全匹配成功的类型。

  2. 先后原则:上述步骤还有多分支,则采取第一个定义的分支函数。

!!! 如果采取了 先后原则,可能无法实现异步定义

如,整个函数链只有 a(),根据先后原则,返回第一个分支函数—— a :: int

匹配子、类型、集合的行为类似。


单子 Just()

Just(1) 只匹配 1,故 Just(1) 是一个 单子

int int 匹配 1 2 也匹配 2 3,故 int int 不是单子,他的 tokens 全由非匹配子组成,他是个 终匹配子

顺序标记

有序匹配子 <int str> 匹配 一个 第一项是int,第二项是str 的序列。

涵序匹配子不关心序列的顺序, [int str] 匹配 int strstr int

因此 [int str] 蕴含 <str int>


数量标记

[int str {..3}] 蕴含 <int><int str><str int>...<str int str>...等1+2+3+4=10 个终匹配子。

同时也蕴含 <int str{2..3}> 子匹配子。


类型、类集、单子、终匹配子的区别

本质上说,类型和匹配子一样,可以匹配实例:

匹配子

    结。


结。 / 匹配子 —— Ruby 的类型论,实现参数多态和交换律、结合律(三)的评论 (共 条)

分享到微博请遵守国家法律