CI/CD流水线创建方法?( 四 )

这将处理运行时才知道的列表中的每个项 。然而,我们仍然可以静态地知道我们将应用于每个项的管道,即使我们不知道项本身是什么 。list_map 本来可以使用 let* 实现,但这样我们就无法静态地看到管道 。
下面是另外两个使用 dart 方法的示例:
let example2 commit =let src = https://www.isolves.com/it/cxkf/bk/2021-02-19/fetch commit inlet base = docker_pull "ocaml/opam2" inlet build ocaml_version =let dockerfile =let+ base = base inmake_dockerfile ~base ~ocaml_version inlet image = build ~dockerfile src ~label:ocaml_version intest imageinall [build "4.07";build "4.08"]与原来相比,我们有一个 all 来合并结果,并且在计算 dockerfile 时有一个额外的 let+base=base 。let+ 只是 map 的另一种语法,在这里使用,因为我选择不更改 make_dockerfile 的签名 。或者,我们可以让你的 dockerfile 接受一个基本图像的承诺,并在里面做地图 。因为 map 需要一个纯实体(make_dockerfile 只生成一个字符串;没有承诺或错误),所以它不需要在图表上有自己的框,并且我们不会因为允许使用它而丢失任何东西 。
let example3 commit =let src = https://www.isolves.com/it/cxkf/bk/2021-02-19/fetch commit inlet image = build src inlet ok = test image inlet revdeps = get_revdeps src ingate revdeps ~on:ok |>list_iter ~pp:Fmt.string example1这显示了另一个自定义操作:gate revdeps~on:ok 是一个承诺,只有在 revdeps 和 ok 都解决后才能解决 。这将阻止它在库自己的测试通过之前测试库的 revdeps,即使如果我们希望它可以并行地这样做 。而对于 monad,我们必须在需要的地方显式地启用并发(使用和 *),而对于 dart,我们必须在不需要的地方显式地禁用并发(使用 gate) 。
我还添加了一个 list-iter 便利函数,并为它提供了一个漂亮的 printer 参数,这样一旦知道列表输入,我们就可以在图表中标记案例 。
最后,虽然我说过不能在原语中使用 let*,但仍然可以使用其他一些 monad(它不会生成图) 。实际上,在实际系统中,我对原语使用了一个单独的 let>操作符 。这就要求主体使用底层 promise 库提供的非图生成承诺,因此不能在原语的主体中使用 let*(或 let>) 。
和 Arrow 进行比较给定一个“dart”,您可以通过定义例如 。
type ('a, 'b) arrow = 'a promise -> 'b promise那么 arr 就是 map,f>>>g 就是有趣的 x->g(fx) 。第一个也可以很容易地定义,假设你有某种函数来并行地做两件事(比如上面的和我们的) 。
因此,dart API(即使有 let*hidden)仍然足以表示任何可以使用箭头 API 表示的管道 。
Haskell 箭头教程 使用一个箭头是有状态函数的示例 。例如,有一个 total 箭头,它返回它的输入和以前调用它的每个输入的总和 。e、 g. 用输入 1 2 3 调用三次,产生输出 1 3 6 。对输入序列运行管道将返回输出序列 。
本教程使用 total 定义 mean1 函数,如下所示:
mean1 = (total &&& (arr (const 1) >>> total)) >>> arr (uncurry (/))因此,此管道复制每个输入编号,将第二个编号替换为 1,将两个流相加,然后用其比率替换每对 。每次将另一个数字放入管道时,都会得到迄今为止输入的所有值的平均值 。
使用 dart 样式的等效代码是(OCaml 使用 / 。对于浮点除法):
let mean values =let t = total values inlet n = total (const 1.0) inmap (uncurry (/.)) (pair t n)这对我来说更容易理解 。通过定义标准运算符 let+(对于 map)和 +(对于 pair),我们可以稍微简化代码:
let (let+) x f = map f xlet (and+) = pairlet mean values =let+ t = total valuesand+ n = total (const 1.0) int /. n无论如何,这不是一个很好的箭头示例,因为我们不使用一个状态函数的输出作为另一个状态函数的输入,所以这实际上只是一个简单的 Applicative.
不过,我们可以很容易地用另一个有状态函数扩展示例管道,也许可以添加一些平滑处理 。这看起来像箭头符号中的 mean1>>>平滑,省道符号中的值|>平均值|>平滑(或平滑(平均值)) 。
注意:Haskell 还有一个 Arrows 语法扩展,它允许 Haskell 代码编写为:
mean2 = proc value -> dot <- total -< valuen <- total -< 1returnA -< t / n这更像是飞镖符号 。
更多示例我在 ocurrent/ocurrent 上建立了一个使用这些思想的稍微扩展版本的库 。子目录 lib_term 是与这篇博客文章相关的部分,在 TERM 中描述了各种组合词 。
其他目录处理更具体的细节,例如与 Lwt promise 库的集成,提供管理 web UI 或 Cap’n Proto RPC 接口,以及带有用于使用 Git、GitHub、Docker 和 Slack 的原语的插件 。


推荐阅读