src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/builtin_fn_flow.d.elv (about) 1 # Run several callables in parallel, and wait for all of them to finish. 2 # 3 # If one or more callables throw exceptions, the other callables continue running, 4 # and a composite exception is thrown when all callables finish execution. 5 # 6 # The behavior of `run-parallel` is consistent with the behavior of pipelines, 7 # except that it does not perform any redirections. 8 # 9 # Here is an example that lets you pipe the stdout and stderr of a command to two 10 # different commands in order to independently capture the output of each byte stream: 11 # 12 # ```elvish-transcript 13 # ~> use file 14 # ~> fn capture {|f| 15 # var pout = (file:pipe) 16 # var perr = (file:pipe) 17 # var out err 18 # run-parallel { 19 # $f > $pout[w] 2> $perr[w] 20 # file:close $pout[w] 21 # file:close $perr[w] 22 # } { 23 # set out = (slurp < $pout[r]) 24 # file:close $pout[r] 25 # } { 26 # set err = (slurp < $perr[r]) 27 # file:close $perr[r] 28 # } 29 # put $out $err 30 # } 31 # ~> capture { echo stdout-test; echo stderr-test >&2 } 32 # ▶ "stdout-test\n" 33 # ▶ "stderr-test\n" 34 # ``` 35 # 36 # This command is intended for doing a fixed number of heterogeneous things in 37 # parallel. If you need homogeneous parallel processing of possibly unbound data, 38 # use `peach` instead. 39 # 40 # See also [`peach`](). 41 fn run-parallel {|@callable| } 42 43 # Calls `$f` on each [value input](#value-inputs). 44 # 45 # An exception raised from [`break`]() is caught by `each`, and will cause it to 46 # terminate early. 47 # 48 # An exception raised from [`continue`]() is swallowed and can be used to 49 # terminate a single iteration early. 50 # 51 # Examples: 52 # 53 # ```elvish-transcript 54 # ~> range 5 8 | each {|x| * $x $x } 55 # ▶ (num 25) 56 # ▶ (num 36) 57 # ▶ (num 49) 58 # ~> each {|x| put $x[..3] } [lorem ipsum] 59 # ▶ lor 60 # ▶ ips 61 # ``` 62 # 63 # See also [`peach`](). 64 # 65 # Etymology: Various languages, as `for each`. Happens to have the same name as 66 # the iteration construct of 67 # [Factor](http://docs.factorcode.org/content/word-each,sequences.html). 68 fn each {|f inputs?| } 69 70 # Calls `$f` for each [value input](#value-inputs), possibly in parallel. 71 # 72 # Like `each`, an exception raised from [`break`]() will cause `peach` to 73 # terminate early. However due to the parallel nature of `peach`, the exact time 74 # of termination is non-deterministic, and termination is not guaranteed. 75 # 76 # An exception raised from [`continue`]() is swallowed and can be used to 77 # terminate a single iteration early. 78 # 79 # The `&num-workers` option restricts the number of functions that may run in 80 # parallel, and must be either an exact positive or `+inf`. A value of `+inf` 81 # (the default) means no restriction. Note that `peach &num-workers=1` is 82 # equivalent to `each`. 83 # 84 # Example (your output will differ): 85 # 86 # ```elvish-transcript 87 # //skip-test 88 # ~> range 1 10 | peach {|x| + $x 10 } 89 # ▶ (num 12) 90 # ▶ (num 13) 91 # ▶ (num 11) 92 # ▶ (num 16) 93 # ▶ (num 18) 94 # ▶ (num 14) 95 # ▶ (num 17) 96 # ▶ (num 15) 97 # ▶ (num 19) 98 # ~> range 1 101 | 99 # peach {|x| if (== 50 $x) { break } else { put $x } } | 100 # + (all) # 1+...+49 = 1225; 1+...+100 = 5050 101 # ▶ (num 1328) 102 # ``` 103 # 104 # This command is intended for homogeneous processing of possibly unbound data. If 105 # you need to do a fixed number of heterogeneous things in parallel, use 106 # `run-parallel`. 107 # 108 # See also [`each`]() and [`run-parallel`](). 109 fn peach {|&num-workers=(num +inf) f inputs?| } 110 111 # Throws an exception; `$v` may be any type. If `$v` is already an exception, 112 # `fail` rethrows it. 113 # 114 # ```elvish-transcript 115 # ~> fail bad 116 # Exception: bad 117 # [tty]:1:1-8: fail bad 118 # ~> put ?(fail bad) 119 # ▶ [^exception &reason=[^fail-error &content=bad &type=fail] &stack-trace=<...>] 120 # ~> fn f { fail bad } 121 # ~> fail ?(f) 122 # Exception: bad 123 # [tty]:1:8-16: fn f { fail bad } 124 # [tty]:1:8-8: fail ?(f) 125 # ``` 126 fn fail {|v| } 127 128 # Raises the special "return" exception. When raised inside a named function 129 # (defined by the [`fn` keyword](language.html#fn)) it is captured by the 130 # function and causes the function to terminate. It is not captured by an 131 # ordinary anonymous function. 132 # 133 # Because `return` raises an exception it can be caught by a 134 # [`try`](language.html#try) block. If not caught, either implicitly by a 135 # named function or explicitly, it causes a failure like any other uncaught 136 # exception. 137 # 138 # See the discussion about [flow commands and 139 # exceptions](language.html#exception-and-flow-commands) 140 # 141 # **Note**: If you want to shadow the builtin `return` function with a local 142 # wrapper, do not define it with `fn` as `fn` swallows the special exception 143 # raised by return. Consider this example: 144 # 145 # ```elvish-transcript 146 # ~> use builtin 147 # ~> fn return { put return; builtin:return } 148 # ~> fn test-return { put before; return; put after } 149 # ~> test-return 150 # ▶ before 151 # ▶ return 152 # ▶ after 153 # ``` 154 # 155 # Instead, shadow the function by directly assigning to `return~`: 156 # 157 # ```elvish-transcript 158 # ~> use builtin 159 # ~> var return~ = { put return; builtin:return } 160 # ~> fn test-return { put before; return; put after } 161 # ~> test-return 162 # ▶ before 163 # ▶ return 164 # ``` 165 fn return { } 166 167 # Raises the special "break" exception. When raised inside a loop it is 168 # captured and causes the loop to terminate. 169 # 170 # Because `break` raises an exception it can be caught by a 171 # [`try`](language.html#try) block. If not caught, either implicitly by a loop 172 # or explicitly, it causes a failure like any other uncaught exception. 173 # 174 # See the discussion about [flow commands and exceptions](language.html#exception-and-flow-commands) 175 # 176 # **Note**: You can create a `break` function and it will shadow the builtin 177 # command. If you do so you should explicitly invoke the builtin. For example: 178 # 179 # ```elvish-transcript 180 # ~> use builtin 181 # ~> fn break { put 'break'; builtin:break; put 'should not appear' } 182 # ~> for x [a b c] { put $x; break; put 'unexpected' } 183 # ▶ a 184 # ▶ break 185 # ``` 186 fn break { } 187 188 # Raises the special "continue" exception. When raised inside a loop it is 189 # captured and causes the loop to begin its next iteration. 190 # 191 # Because `continue` raises an exception it can be caught by a 192 # [`try`](language.html#try) block. If not caught, either implicitly by a loop 193 # or explicitly, it causes a failure like any other uncaught exception. 194 # 195 # See the discussion about [flow commands and exceptions](language.html#exception-and-flow-commands) 196 # 197 # **Note**: You can create a `continue` function and it will shadow the builtin 198 # command. If you do so you should explicitly invoke the builtin. For example: 199 # 200 # ```elvish-transcript 201 # ~> use builtin 202 # ~> fn continue { put 'continue'; builtin:continue; put 'should not appear' } 203 # ~> for x [a b c] { put $x; continue; put 'unexpected' } 204 # ▶ a 205 # ▶ continue 206 # ▶ b 207 # ▶ continue 208 # ▶ c 209 # ▶ continue 210 # ``` 211 fn continue { } 212 213 # Schedules a function to be called when execution reaches the end of the 214 # current closure. The function is called with no arguments or options, and any 215 # exception it throws gets propagated. 216 # 217 # Examples: 218 # 219 # ```elvish-transcript 220 # ~> { defer { put foo }; put bar } 221 # ▶ bar 222 # ▶ foo 223 # ~> defer { put foo } 224 # Exception: defer must be called from within a closure 225 # [tty]:1:1-17: defer { put foo } 226 # ``` 227 fn defer {|fn| }