// Definition of an infinite linked list#List: { data: _ next: #List |*null// note, the default to null is required// otherwise it looks like a cyclic reference}// manually construct a linked listl: #List & {data: 1, next: #List & {data: 2}}ds: [1, 2, 4, 8]// comprehend a linked list from some datall: [ for i, d in ds { data: dif i <len(ds)-1 { next: ll[i+1] // note how we reference "future" list elements! }}]L: ll[0] // we really only want the first element
你可以在 GitHub/cuetils 这个项目中找到相关代码和例子,
以及很多关于 “递归” 的辅助函数,在那你也可以找到函数的 Go 版本。
对于任何正规的使用,强烈建议使用有递归支持的语言。Cuetils 以 Go 包也提供相同的辅助函数,支持 CUE 值作为参数。
当使用 RecurseN 的 CUE 版本和用它构建的“递归”函数时,可能会出现性能问题。
recurse.cue
packagerimport"list"#RecurseN: {// this is the bound on our recursion #maxiter: uint|*4// This is the function list element// we generate this to simulate recursion #funcFactory: { #next: _ #func: _ }// this is our "recursion unrolling"for k, v inlist.Range(0, #maxiter, 1) {// this is where we build up our indexed functions and the references between them #funcs: "\(k)": (#funcFactory & {#next: #funcs["\(k+1)"]}).#func }// our final value needs to be null #funcs: "\(#maxiter)": null// we embed the head of the list so that the values// we write this into can be used like other CUE "functions" #funcs["0"]}
depth.cue
packagerimport"list"#DepthF: { #next: _ #func: { #in: _ #basic: int|number|string|bytes|null out: {// if we have a basic type, we are at a leaf, depth is 1if (#in & #basic) !=_|_ {1}// if we are not a basic type, then we are 1 + the max of childrenif (#in & #basic) ==_|_ {// this is our "recursion" for each childlet depths = [ for k, v in #in {(#next & {#in: v}).out}]list.Max(depths) +1 } } }}#Depth: #RecurseN & {#maxiter: 11, #funcFactory: #DepthF}tree: { a: { foo: "bar" a: b: c: "d" } cow: "moo"}d: #Depth & {#in: tree}
注意 let depths = ... 这一行的 {(#next & {#in: v}).out},这是递归,或者实际上是从一个生成的函数到下一个。
todo, 展示展开的 #Depth 什么样,将会帮助理解。
我们应该明白,这里没有函数、没有调用,也没有递归。
我们真正做的是,将一个未完成的定义然后创建一个排列,让他们指向自己的邻居(#RecurseN 中的 for 推导)。
packager#pickF: { #next: _ #func: { #X: _ #P: _ pick: {// if P is not a complex typeif (#P & ({...} | [...])) ==_|_ {// then take the leaf value if it unifies (note to dev, should there be an if here?) #P & #X }// if P is a complex typeif (#P & ({...} | [...])) !=_|_ {// for each field in Pfor i, p in #P {let x = #X[i]// if they unify (samish type)if (x & p) !=_|_ {// if not a struct, pick the valueif (x & {...}) ==_|_ {"\(i)": x }// if it is a struct, then "recurse"if (x & {...}) !=_|_ {"\(i)": (#next & {#X: x, #P: p}).pick } }// if they do not unifyif (x & p) ==_|_ {// and if struct, then recurseif (x & {...}) !=_|_ {"\(i)": (#next & {#X: x, #P: p}).pick } } } } } }}#Pick: #RecurseN & {#funcFactory: #pickF}tree: { a: { foo: "bar" a: b: c: "d" } cow: "moo"}P: { a: foo: string cow: "moo"}p: #pick & {#X: tree, #P: P}
diff.cue
packager#DiffF: { #next: _ #func: { #X: _ #Y: _ diff: { {for i, x in #X {let y = #Y[i]if y ==_|_ {"-": "\(i)": x }if y !=_|_ {if (x & {...}) !=_|_ {"\(i)": (#next & {#X: x, #Y: y}).diff }if (x & {...}) ==_|_ {if (x & y) ==_|_ {"-": "\(i)": x"+": "\(i)": y } } } } }"+": {for i, y in #Y {if #X[i] ==_|_ {"\(i)": y } } } } }}#diff: #RecurseN & {#funcFactory: #DiffF}ex: { x: { a: "a" b: "b" d: "d" e: { a: "a" b: "b" d: "d" } } y: { b: "b" c: "c" d: "D" e: { b: "b" c: "c" d: 1 } } diff: (#diff & {#X: x, #Y: y}).diff}