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

Then, example2 changes from:
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 = make_dockerfile ~base ~ocaml_version inlet image = build ~dockerfile src ~label:ocaml_version intest imageinbuild "4.07";build "4.08"to:
let example2 =let build ocaml_version =first (arr (fun base -> make_dockerfile ~base ~ocaml_version))>>> build_with_dockerfile ~label:ocaml_version>>> testinarr (fun c -> ((), c))>>> (docker_pull "ocaml/opam2" *** fetch)>>> (build "4.07" &&& build "4.08")>>> arr (fun ((), ()) -> ())我们已经丢失了大多数变量名,而不得不使用元组,记住我们的值在哪里 。这里有两个值并不是很糟糕,但是随着更多的值被添加并且我们开始嵌套元组,它变得非常困难 。我们还失去了在 build~dockerfile src 中使用可选标记参数的能力,而是需要使用一个新操作,该操作接受 dockerfile 和源的元组 。
假设现在运行测试需要从源代码获取测试用例 。在原始代码中,我们只需使用:src 将测试图像更改为测试图像 。在 arrow 版本中,我们需要在生成步骤之前复制源代码,使用带 dockerfile 的 first build_ 运行生成,并确保参数是新测试使用的正确方法 。
Dart 方法我开始怀疑是否有一种更简单的方法来实现与箭头相同的静态分析,但是没有无点语法,而且似乎有 。考虑示例 1 的一元版本 。我们有:
val build : source -> image promiseval test : image -> results promiselet example1 commit =let* src = https://www.isolves.com/it/cxkf/bk/2021-02-19/fetch commit inlet* image = build src intest image如果你不知道蒙娜兹的事,你还有别的办法 。您可以定义 build 和 test,将 promises 作为输入,而不是使用 let* 等待获取完成,然后使用源调用 build:
val build : source promise -> image promiseval test : image promise -> results promise毕竟,fetching 给了你一个源代码承诺,你想要一个图像承诺,所以这看起来很自然 。我们甚至可以以承诺为例 。然后看起来是这样的:
let example1 commit =let src = https://www.isolves.com/it/cxkf/bk/2021-02-19/fetch commit inlet image = build src intest image很好,因为它和我们刚开始的简单版本是一样的 。问题是效率低下:

  • 我们用承诺的方式调用 example1(我们还不知道它是什么) 。
  • 我们不必等待找出要测试的提交,而是调用 fetch,获取某个源的承诺 。
  • 不需要等待获取源代码,我们就调用 build,获取图像的承诺 。
  • 不用等待构建,我们调用 test,得到结果的承诺 。
我们立即返回测试结果的最终承诺,但我们还没有做任何真正的工作 。相反,我们建立了一长串的承诺,浪费了记忆 。
但是,在这种情况下,我们希望执行静态分析 。i、 我们想在内存中建立一些表示流水线的数据结构……这正是我们对 monad 的“低效”使用所产生的结果!
为了使其有用,我们需要基本操作(比如 fetch)来为静态分析提供一些信息(比如标签) 。OCaml 的 let 语法没有为标签提供明显的位置,但是我能够定义一个运算符(let**),该运算符返回一个接受 label 参数的函数 。它可用于生成如下基本操作:
let fetch commit ="fetch" |>let** commit = commit in(* (standard monadic implementation of fetch goes here) *)因此,fetch 接受一个提交的承诺,对它执行一个单字节绑定以等待实际的提交,然后像以前一样继续,但它将绑定标记为一个 fetch 操作 。如果 fetch 包含多个参数,则可以使用 and* 并行等待所有参数 。
理论上,let**In fetch 的主体可以包含进一步的绑定 。如果那样的话,我们在一开始就无法分析整个管道 。但是,只要原语在开始时等待所有输入,并且不在内部进行任何绑定,我们就可以静态地发现整个管道 。
我们可以选择是否将这些绑定操作公开给应用程序代码 。如果 let*(或 let**)被公开,那么应用程序就可以使用 monad 的所有表达能力,但是在某些承诺解决之前,我们将无法显示整个管道 。如果我们隐藏它们,那么应用程序只能生成静态管道 。
到目前为止,我的方法是使用 let* 作为逃生舱口,这样就可以建造任何所需的管道,但我后来用更专业的操作来代替它的任何用途 。例如,我添加了:
val list_map : ('a t -> 'b t) -> 'a list t -> 'b list t


推荐阅读