Repository F# setup
open System
open System.IO
open System.Threading
open System.Threading.Tasks
open Axial
open Axial.Console
open Axial.FileSystem
open Axial.PlatformService
open Axial.ProcessFlowStream integration
The streaming guide covers the short line-consumption path: streamStdoutLines, effectful
consumption, take/takeWhile, and retained output tails. This page covers what needs an ordinary FlowStream: merging
process output with other sources, feeding queues and hubs, folding, stderr provenance, line limits, and conversion.
Lines exclude LF and one preceding CR, preserve blank lines and bare CR, and emit final unterminated text.
maxLineLength defaults to 1,048,576 UTF-16 code units; oversized lines fail with LineTooLong.
Use ProcessStream.toFlowStream when you need an ordinary FlowStream API and can discard successful process completion. The converted stream retains typed process failures, backpressure, and scoped cleanup.
For completion-aware processing, keep transformations and terminals in ProcessStream. After conversion,
application callback deadlines belong to the enclosing Flow; use Flow.timeout to bound them.
ProcessStream terminals include callbacks in the process overall timeout.
Combine streams or feed a queue or hub
Convert with ProcessStream.toFlowStream when process output becomes one source in a larger stream.
FlowStream.mergePar interleaves sources as values arrive; zip pairs their values. The sources must have
compatible environment, error, and value types; use FlowStream.mapError to align different error types.
Show page setup
// Setup for the checked examples on this page.
open Axial
open Axial.Process
open Axial.Process.DSL
/// Fails the docs test when an example's result differs from the value shown.
let shouldEqual expected actual =
if actual <> expected then failwithf "Expected %A but got %A" expected actuallet processLines =
cmd $"printf 'process 1\nprocess 2\n'" |> streamStdoutLines |> ProcessStream.toFlowStream
let applicationLines = FlowStream.fromSeq ["application 1"; "application 2"]
let combined = [processLines; applicationLines] |> FlowStream.mergePar |> FlowStream.runCollect
combined |> Process.run |> List.sort
|> shouldEqual ["application 1"; "application 2"; "process 1"; "process 2"]
processLines: FlowStream<ProcessHostEnvironment,ProcessError,string>cmd: FormattableString -> ProcessCommand(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
streamStdoutLines: ^a -> ProcessStream<'b,string>Axial.Process.ProcessStreamtoFlowStream: ProcessStream<'a,'b> -> FlowStream<'a,ProcessError,'b>Converts to ordinary FlowStream, discarding successful process completion.
applicationLines: FlowStream<ProcessHostEnvironment,ProcessError,string>Axial.FlowStreamModulefromSeq: 'value seq -> FlowStream<'env,'error,'value>Creates a stream from a synchronous sequence of values. The sequence of values to be emitted by the stream. A that yields each value from the sequence. FlowStream.fromSeq [1..10] |> FlowStream.runCollect |> Flow.run ()
combined: Flow<ProcessHostEnvironment,ProcessError,string list>mergePar: FlowStream<'env,'error,'value> list -> FlowStream<'env,'error,'value>Runs several streams concurrently and emits their values as they arrive. Each stream keeps its own order; values from different streams interleave in arrival order. The merged stream ends when every stream has ended. The first failure is delivered after the values already buffered, and the other streams are interrupted. When the consumer stops early, every stream is interrupted. [ readerA; readerB; readerC ] |> FlowStream.mergePar |> FlowStream.runIntoQueue controlInputs
runCollect: FlowStream<'a,'b,'c> -> Flow<'a,'b,'c list>Collects all emitted values into a list. stream |> FlowStream.runCollect
Axial.Process.Processrun: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
Microsoft.FSharp.Collections.ListModuleContains operations for working with values of type . Operations for collections such as lists, arrays, sets, maps and sequences. See also F# Collection Types in the F# Language Guide.
sort: 'T list -> 'T listSorts the given list using . This is a stable sort, i.e. the original order of equal elements is preserved. This is an O(n log n) operation, where n is the length of the list. The input list. The sorted list. let input = [8; 4; 3; 1; 6; 1] List.sort input Evaluates to [1; 1; 3; 4; 6; 8].
shouldEqual: 'a -> 'a -> unitRequires & types
Requires: open Axial; open Axial.Process; open Axial.Process.DSL (packages: Axial, Axial.Process)val processLines: FlowStream<ProcessHostEnvironment,ProcessError,string>val applicationLines: FlowStream<ProcessHostEnvironment,ProcessError,string>val combined: Flow<ProcessHostEnvironment,ProcessError,string list>FlowStream.runIntoQueue offers each value to a queue; runIntoHub publishes it to the hub's current
subscribers. Both return a lazy Flow to bind in your application. A bounded queue or a hub subscription
using BackPressure slows the producer when full. Start the consumer concurrently for a bounded buffer;
hub subscriptions must exist before publishing. These terminals leave the queue or hub open so other
producers can keep using it.
let queued = flow {
let! queue = Queue.unbounded ()
do! cmd $"printf 'first\nsecond\n'"
|> streamStdoutLines |> ProcessStream.toFlowStream |> FlowStream.runIntoQueue queue
return! Dequeue.takeAll queue
}
queued |> Process.run |> shouldEqual ["first"; "second"]
let published =
flow {
let! hub = Hub.make ()
let! subscription = hub |> Hub.subscribe QueueStrategy.Unbounded
do! cmd $"printf 'first\nsecond\n'"
|> streamStdoutLines |> ProcessStream.toFlowStream |> FlowStream.runIntoHub hub
return! Dequeue.takeAll subscription
} |> Flow.scoped
published |> Process.run |> shouldEqual ["first"; "second"]
queued: Flow<ProcessHostEnvironment,ProcessError,string list>flow: FlowBuilderThe universal flow { } computation expression.
queue: Queue<string>Axial.QueueModuleCreates queues and offers values to them. Take values, inspect, and shut a queue down with the Dequeue functions.
unbounded: unit -> Flow<'env,'error,Queue<'a>>Creates a queue that never rejects or suspends an offer. Memory grows with the backlog; prefer a bounded queue unless producers are otherwise limited.
cmd: FormattableString -> ProcessCommand(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
streamStdoutLines: ^a -> ProcessStream<'b,string>Axial.Process.ProcessStreamtoFlowStream: ProcessStream<'a,'b> -> FlowStream<'a,ProcessError,'b>Converts to ordinary FlowStream, discarding successful process completion.
Axial.FlowStreamModulerunIntoQueue: Queue<'value> -> FlowStream<'env,'error,'value> -> Flow<'env,'error,unit>Runs a stream and offers every value to a queue, waiting while a bounded queue is full. The queue is not shut down when the stream ends, so several streams can feed one queue; shut it down with Dequeue.shutdown once every producer has finished. If the queue is shut down first, the flow is interrupted. deviceReadings |> FlowStream.runIntoQueue controlInputs
Axial.DequeueModuleTakes values from a , inspects it, and shuts it down. Every function here also accepts a .
takeAll: Dequeue<'a> -> Flow<'env,'error,'a list>Removes every available value in FIFO order, without suspending.
Axial.Process.Processrun: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
shouldEqual: 'a -> 'a -> unitpublished: Flow<ProcessHostEnvironment,ProcessError,string list>hub: Hub<string>Axial.HubModuleCreates hubs, publishes to them, and subscribes to them. A publish reaches every subscription that exists when it starts; a subscriber sees only values published after its subscribe completes, so a late joiner that needs current state must get it elsewhere, for example from a SubscriptionRef. Publishes are serialized, so every subscriber observes values in the same order even with concurrent publishers. Dropping, Sliding, and Unbounded subscriptions never delay the publisher. A BackPressure subscription with a full buffer suspends publish until it has room or its subscription ends. While the publisher waits, no later value reaches any subscriber, lossy ones included: keeping one order for every subscriber means a stalled lossless subscriber stalls the feed. Size a lossless subscriber's buffer for the bursts you expect, watch Dequeue.size to raise an alarm before it fills, and use Hub.tryPublish where the publisher must never wait. Shutting a hub down shuts every subscription down with Dequeue.shutdown semantics: subscribers drain their backlog, streams over subscriptions end normally, and later publishes are interrupted.
make: unit -> Flow<'env,'error,Hub<'a>>Creates a hub with no subscriptions.
subscription: Dequeue<string>subscribe: QueueStrategy -> Hub<'a> -> Flow<'env,'error,Dequeue<'a>>Subscribes to the hub with a buffering strategy. The subscription ends when the current scope closes. Run subscribe inside Flow.scoped, a forked fiber, or an application root: a forked fiber's subscription ends with the fiber. Ending the subscription, by closing its scope or with Dequeue.shutdown, removes it from the hub and releases a publisher waiting on it. To subscribe for the life of a stream, use FlowStream.fromHub. flow { let! (readings: Hub<float>) = Hub.make () let! latest = readings |> Hub.subscribe (QueueStrategy.Sliding 1) do! readings |> Hub.publishAll [ 20.0; 21.5 ] |> Flow.ignore return! Dequeue.takeAll latest } |> Flow.scoped
Axial.QueueStrategyWhat a queue, or a hub subscription, does with a value offered while it is full. Lossless delivery needs either back-pressure or unbounded memory. BackPressure keeps every value by making the producer wait; Unbounded keeps every value by growing without limit; Dropping and Sliding never make the producer wait and lose values instead. A non-positive capacity fails the flow that uses the strategy with a defect.
UnboundedLossless and never suspends the producer; memory grows with the backlog.
runIntoHub: Hub<'value> -> FlowStream<'env,'error,'value> -> Flow<'env,'error,unit>Runs a stream and publishes every value to a hub. Each value is published with Hub.publish, so a full BackPressure subscription slows the stream down. If the hub is shut down first, the flow is interrupted. sensor |> FlowStream.runIntoHub readings
Axial.Flowscoped: Flow<'env,'error,'value> -> Flow<'env,'error,'value>Runs a flow in a child scope and closes that scope before returning. Resources and fibers acquired inside the flow are released after success, typed failure, defect, or interruption without waiting for the surrounding application scope to close.
Requires & types
Requires: open Axial; open Axial.Process; open Axial.Process.DSL (packages: Axial, Axial.Process)val queued: Flow<ProcessHostEnvironment,ProcessError,string list>val published: Flow<ProcessHostEnvironment,ProcessError,string list>If you need the final exit details as well as the published values, keep the ProcessStream and send
values with runForEachFlow. The resulting Flow returns ProcessCompletion and keeps process and
consumer failures distinct. The same pattern works with Hub.publish line hub |> Flow.ignore.
let queuedWithCompletion = flow {
let! queue = Queue.unbounded ()
let! completion =
cmd $"printf 'first\nsecond\n'" |> streamStdoutLines
|> ProcessStream.runForEachFlow (fun line ->
Queue.offer line queue |> Flow.ignore : Flow<_, Never, unit>)
let! values = Dequeue.takeAll queue
return values, completion
}
let queuedValues, queuedCompletion = queuedWithCompletion |> Process.run
shouldEqual ["first"; "second"] queuedValues
match queuedCompletion with
| ProcessCompletion.Completed result -> shouldEqual 0 result.ExitCode
| ProcessCompletion.StoppedEarly -> failwith "Expected completed output"
queuedWithCompletion: Flow<ProcessHostEnvironment,ProcessStreamError<Never>,(string list * ProcessCompletion)>flow: FlowBuilderThe universal flow { } computation expression.
queue: Queue<string>Axial.QueueModuleCreates queues and offers values to them. Take values, inspect, and shut a queue down with the Dequeue functions.
unbounded: unit -> Flow<'env,'error,Queue<'a>>Creates a queue that never rejects or suspends an offer. Memory grows with the backlog; prefer a bounded queue unless producers are otherwise limited.
completion: ProcessCompletioncmd: FormattableString -> ProcessCommand(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
streamStdoutLines: ^a -> ProcessStream<'b,string>Axial.Process.ProcessStreamrunForEachFlow: ('a -> Flow<'b,'c,unit>) -> ProcessStream<'b,'a> -> Flow<'b,ProcessStreamError<'c>,ProcessCompletion>Runs each callback in the application environment; preserves consumer errors separately.
line: stringoffer: 'a -> Queue<'a> -> Flow<'env,'error,bool>Adds a value according to the queue's strategy. true when the value was accepted, or false when a dropping queue discarded it. A bounded queue suspends until space exists. The flow is interrupted if the queue is or becomes shut down first. flow { let! (jobs: Queue<string>) = Queue.bounded 8 return! jobs |> Queue.offer "job" }
Axial.Flowignore: Flow<'env,'error,'value> -> Flow<'env,'error,unit>Maps the successful value of a synchronous flow to unit. The source flow. A flow that succeeds with unit instead of the original value. let flow = Flow.succeed 42 |> Flow.ignore
Axial.Flow`3Axial.NeverRepresents an error channel that cannot occur.
unitThe type 'unit', which has only one value "()". This value is special and always uses the representation 'null'. Basic Types
values: string listAxial.DequeueModuleTakes values from a , inspects it, and shuts it down. Every function here also accepts a .
takeAll: Dequeue<'a> -> Flow<'env,'error,'a list>Removes every available value in FIFO order, without suspending.
queuedValues: string listqueuedCompletion: ProcessCompletionAxial.Process.Processrun: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
shouldEqual: 'a -> 'a -> unitAxial.Process.ProcessCompletionCompletedresult: ProcessResultExitCode: intStoppedEarlyfailwith: string -> 'TThrow a exception. The exception message. Never returns. let failingFunction() = failwith "Oh no" // Throws an exception true // Never reaches this failingFunction() // Throws a System.Exception
Requires & types
Requires: open Axial; open Axial.Process; open Axial.Process.DSL (packages: Axial, Axial.Process)val queuedWithCompletion: Flow<ProcessHostEnvironment,ProcessStreamError<Never>,(string list * ProcessCompletion)>val queuedValues: string listval queuedCompletion: ProcessCompletionTransform and fold without collecting every item
Keep ProcessStream.map and filter on the process stream when completion matters. runFold reduces output
in memory; runFoldFlow lets each step use application services or fail with an application error.
let numbers () = cmd $"printf '1\n2\n3\n4\n'" |> streamStdoutLines
let evenTotal =
numbers () |> ProcessStream.map int |> ProcessStream.filter (fun value -> value % 2 = 0)
|> ProcessStream.runFold (+) 0
let total, _ = evenTotal |> Process.run
shouldEqual 6 total
let checkedTotal =
numbers ()
|> ProcessStream.runFoldFlow
(fun total text -> (Flow.ok (total + int text) : Flow<_, string, int>))
0
let checkedSum, _ = checkedTotal |> Process.run
shouldEqual 10 checkedSum
let observed = ResizeArray<string>()
numbers () |> ProcessStream.runForEach observed.Add |> Process.run |> ignore
shouldEqual ["1"; "2"; "3"; "4"] (List.ofSeq observed)
numbers: unit -> ProcessStream<'a,string>cmd: FormattableString -> ProcessCommand(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
streamStdoutLines: ^a -> ProcessStream<'b,string>evenTotal: Flow<ProcessHostEnvironment,ProcessError,(int * ProcessCompletion)>Axial.Process.ProcessStreammap: ('a -> 'b) -> ProcessStream<'c,'a> -> ProcessStream<'c,'b>Transforms values while preserving process completion.
int: ^T -> intConverts the argument to signed 32-bit integer. This is a direct conversion for all primitive numeric types. For strings, the input is converted using Int32.Parse() with InvariantCulture settings. Otherwise the operation requires an appropriate static conversion method on the input type. The input value. The converted int int 'A' // evaluates to 65 int 0xff // evaluates to 255 int -10 // evaluates to -10
filter: ('a -> bool) -> ProcessStream<'b,'a> -> ProcessStream<'b,'a>Selects values without losing process completion or skipping drainage of other channels.
value: int(%): ^T1 -> ^T2 -> ^T3Overloaded modulo operator The first parameter. The second parameter. The result of the operation. 29 % 5 // Evaluates to 4
(=): 'T -> 'T -> boolStructural equality The first parameter. The second parameter. The result of the comparison. 5 = 5 // Evaluates to true 5 = 6 // Evaluates to false [1; 2] = [1; 2] // Evaluates to true (1, 5) = (1, 6) // Evaluates to false
runFold: ('a -> 'b -> 'a) -> 'a -> ProcessStream<'c,'b> -> Flow<'c,ProcessError,('a * ProcessCompletion)>Folds selected values and returns the state together with completion; capture policy is independent.
(+): ^T1 -> ^T2 -> ^T3Overloaded addition operator The first parameter. The second parameter. The result of the operation. 2 + 2 // Evaluates to 4 "Hello " + "World" // Evaluates to "Hello World"
total: intAxial.Process.Processrun: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
shouldEqual: 'a -> 'a -> unitcheckedTotal: Flow<ProcessHostEnvironment,ProcessStreamError<string>,(int * ProcessCompletion)>runFoldFlow: ('a -> 'b -> Flow<'c,'d,'a>) -> 'a -> ProcessStream<'c,'b> -> Flow<'c,ProcessStreamError<'d>,('a * ProcessCompletion)>Folds with application workflows; typed consumer failures use ConsumerFailed.
text: stringAxial.Flowok: 'value -> Flow<'env,'error,'value>Creates a successful synchronous flow. The value to wrap in a successful flow. A flow that always succeeds with the provided value.
Axial.Flow`3stringAn abbreviation for the CLI type . Basic Types
intAn abbreviation for the CLI type . Basic Types
checkedSum: intobserved: ResizeArray<string>``.ctor``: unit -> unitInitializes a new instance of the class that is empty and has the default initial capacity.
runForEach: ('a -> unit) -> ProcessStream<'b,'a> -> Flow<'b,ProcessError,ProcessCompletion>Synchronous callback; use runForEachFlow for explicit service operations.
Add: string -> unitAdds an object to the end of the . The object to be added to the end of the . The value can be for reference types.
ignore: 'T -> unitIgnore the passed value. This is often used to throw away results of a computation. The value to ignore. ignore 55555 // Evaluates to ()
Microsoft.FSharp.Collections.ListModuleContains operations for working with values of type . Operations for collections such as lists, arrays, sets, maps and sequences. See also F# Collection Types in the F# Language Guide.
ofSeq: 'T seq -> 'T listBuilds a new list from the given enumerable object. The input sequence. The list of elements from the sequence. let inputs = seq { 1; 2; 5 } inputs |> List.ofSeq Evaluates to [ 1; 2; 5 ]. This is an O(n) operation, where n is the length of the sequence.
Requires & types
Requires: open Axial; open Axial.Process; open Axial.Process.DSL (packages: Axial, Axial.Process)val numbers: unit -> ProcessStream<'a,string>val evenTotal: Flow<ProcessHostEnvironment,ProcessError,(int * ProcessCompletion)>val total: intval checkedTotal: Flow<ProcessHostEnvironment,ProcessStreamError<string>,(int * ProcessCompletion)>val checkedSum: intval observed: ResizeArray<string>Use runForEachFlow or runFoldFlow for dependencies such as IConsole; those effects remain explicit in the environment. Typed consumer errors become
ProcessStreamError.ConsumerFailed, while process failures become ProcessFailed.
let rejected =
cmd $"printf 'ready\n'" |> streamStdoutLines
|> ProcessStream.runForEachFlow (fun _ -> Flow.fail "rejected record")
match rejected |> Process.tryRun with
| Exit.Failure(Cause.Fail(ProcessStreamError.ConsumerFailed message)) ->
shouldEqual "rejected record" message
| other -> failwithf "Expected consumer failure, got %A" other
let prefix =
cmd $"printf 'ready\nstop\nlater\n'" |> streamStdoutLines
|> ProcessStream.takeWhile (fun line -> line <> "stop") |> ProcessStream.runCollect
prefix |> Process.run |> shouldEqual (["ready"], ProcessCompletion.StoppedEarly)
rejected: Flow<ProcessHostEnvironment,ProcessStreamError<string>,ProcessCompletion>cmd: FormattableString -> ProcessCommand(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
streamStdoutLines: ^a -> ProcessStream<'b,string>Axial.Process.ProcessStreamrunForEachFlow: ('a -> Flow<'b,'c,unit>) -> ProcessStream<'b,'a> -> Flow<'b,ProcessStreamError<'c>,ProcessCompletion>Runs each callback in the application environment; preserves consumer errors separately.
Axial.Flowfail: 'error -> Flow<'env,'error,'value>Same as error. The error value to wrap in a failing flow. A flow that always fails with the provided error. let result = Flow.fail "error" |> Flow.run () // result = Failure (Cause.Fail "error")
Axial.Process.ProcesstryRun: ^source -> ^resultRuns with live services and returns Exit, including typed failures and interruptions.
Axial.Exit`2Represents the final outcome of a workflow execution. The type of the success value. The type of the domain-specific failure value.
FailureThe workflow failed due to a specific cause.
Axial.Cause`1Represents the cause of a failed workflow. The type of the domain-specific failure value.
FailAn expected domain-specific failure.
Axial.Process.ProcessStreamError`1ConsumerFailedmessage: stringshouldEqual: 'a -> 'a -> unitother: Exit<ProcessCompletion,ProcessStreamError<string>>failwithf: Printf.StringFormat<'T,'Result> -> 'TPrint to a string buffer and raise an exception with the given result. Helper printers must return strings. The formatter. The formatted result. See Printf.failwithf (link: ) for examples.
prefix: Flow<ProcessHostEnvironment,ProcessError,(string list * ProcessCompletion)>takeWhile: ('a -> bool) -> ProcessStream<'b,'a> -> ProcessStream<'b,'a>Stops before the first nonmatching value, awaits owned cleanup, and reports StoppedEarly.
line: string(<>): 'T -> 'T -> boolStructural inequality The first parameter. The second parameter. The result of the comparison. 5 <> 5 // Evaluates to false 5 <> 6 // Evaluates to true [1; 2] <> [1; 2] // Evaluates to false
runCollect: ProcessStream<'a,'b> -> Flow<'a,ProcessError,('b list * ProcessCompletion)>Collects every selected value plus completion. The collected list can grow without bound.
run: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
Axial.Process.ProcessCompletionStoppedEarlyRequires & types
Requires: open Axial; open Axial.Process; open Axial.Process.DSL (packages: Axial, Axial.Process)val rejected: Flow<ProcessHostEnvironment,ProcessStreamError<string>,ProcessCompletion>val prefix: Flow<ProcessHostEnvironment,ProcessError,(string list * ProcessCompletion)>Observe stderr and channel provenance
Use streamStderrLines for stderr alone. With streamOutputs, keep the metadata to distinguish stage and
original channel even after merging. Chunk boundaries depend on native reads; reconstruct text per channel
rather than assuming one event per write.
let errors =
sh $"printf data; printf 'warning\n' >&2" |> streamStderrLines |> ProcessStream.runCollect
let errorLines, errorCompletion = errors |> Process.run
shouldEqual ["warning"] errorLines
match errorCompletion with
| ProcessCompletion.Completed result -> shouldEqual "data" result.StdOut
| ProcessCompletion.StoppedEarly -> failwith "Expected completed output"
let outputs =
sh $"printf data; printf warning >&2"
|> mergeStderr
|> streamOutputs
|> ProcessStream.runCollect
let events, _ = outputs |> Process.run
let allStdout = events |> List.forall (fun item -> item.ObservedChannel = OutputChannel.StdOut)
shouldEqual true allStdout
let original channel =
events
|> List.filter (fun item -> item.OriginalChannel = channel)
|> List.map _.Text
|> String.concat ""
shouldEqual "data" (original OutputChannel.StdOut)
shouldEqual "warning" (original OutputChannel.StdErr)
errors: Flow<ProcessHostEnvironment,ProcessError,(string list * ProcessCompletion)>sh: FormattableString -> ProcessCommandBuilds a POSIX shell program with interpolation values passed as positional arguments.
(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
streamStderrLines: ^a -> ProcessStream<'b,string>Axial.Process.ProcessStreamrunCollect: ProcessStream<'a,'b> -> Flow<'a,ProcessError,('b list * ProcessCompletion)>Collects every selected value plus completion. The collected list can grow without bound.
errorLines: string listerrorCompletion: ProcessCompletionAxial.Process.Processrun: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
shouldEqual: 'a -> 'a -> unitAxial.Process.ProcessCompletionCompletedresult: ProcessResultStdOut: stringStoppedEarlyfailwith: string -> 'TThrow a exception. The exception message. Never returns. let failingFunction() = failwith "Oh no" // Throws an exception true // Never reaches this failingFunction() // Throws a System.Exception
outputs: Flow<ProcessHostEnvironment,ProcessError,(ProcessOutput list * ProcessCompletion)>mergeStderr: ^a -> ProcessSpecstreamOutputs: ^a -> ProcessStream<'b,ProcessOutput>events: ProcessOutput listallStdout: boolMicrosoft.FSharp.Collections.ListModuleContains operations for working with values of type . Operations for collections such as lists, arrays, sets, maps and sequences. See also F# Collection Types in the F# Language Guide.
forall: ('T -> bool) -> 'T list -> boolTests if all elements of the collection satisfy the given predicate. The predicate is applied to the elements of the input list. If any application returns false then the overall result is false and no further elements are tested. Otherwise, true is returned. This is an O(n) operation in the worst case, where n is the length of the list. The function to test the input elements. The input list. True if all of the elements satisfy the predicate. let isEven a = a % 2 = 0 [2; 42] |> List.forall isEven // evaluates to true [1; 2] |> List.forall isEven // evaluates to false
item: ProcessOutputObservedChannel: OutputChannel(=): 'T -> 'T -> boolStructural equality The first parameter. The second parameter. The result of the comparison. 5 = 5 // Evaluates to true 5 = 6 // Evaluates to false [1; 2] = [1; 2] // Evaluates to true (1, 5) = (1, 6) // Evaluates to false
Axial.Process.OutputChannelIdentifies one standard output channel.
StdOutoriginal: OutputChannel -> stringchannel: OutputChannelfilter: ('T -> bool) -> 'T list -> 'T listReturns a new collection containing only the elements of the collection for which the given predicate returns "true" The function to test the input elements. The input list. A list containing only the elements that satisfy the predicate. let input = [1, "Luke"; 2, "Kirk"; 3, "Kenobi"; 4, "Spock"] let isEven x = 0 = x % 2 let isComingFromStarTrek (x,_) = isEven x input |> List.filter isComingFromStarTrek Evaluates to [(2, "Kirk"); (4, "Spock")] This is an O(n) operation, where n is the length of the list.
OriginalChannel: OutputChannelmap: ('T -> 'U) -> 'T list -> 'U listBuilds a new collection whose elements are the results of applying the given function to each of the elements of the collection. The function to transform elements from the input list. The input list. The list of transformed elements. let inputs = [ "a"; "bbb"; "cc" ] inputs |> List.map (fun x -> x.Length) Evaluates to [ 1; 3; 2 ] This is an O(n) operation, where n is the length of the list.
_arg1: ProcessOutputText: stringMicrosoft.FSharp.Core.StringModuleFunctional programming operators for string processing. Further string operations are available via the member functions on strings and other functionality in System.String and System.Text.RegularExpressions types. Strings and Text
concat: string -> string seq -> stringReturns a new string made by concatenating the given strings with separator sep, that is a1 + sep + ... + sep + aN. The separator string to be inserted between the strings of the input sequence. The sequence of strings to be concatenated. A new string consisting of the concatenated strings separated by the separation string. Thrown when strings is null. let input1 = ["Stefan"; "says:"; "Hello"; "there!"] input1 |> String.concat " " // evaluates "Stefan says: Hello there!" let input2 = [0..9] |> List.map string input2 |> String.concat "" // evaluates "0123456789" input2 |> String.concat ", " // evaluates "0, 1, 2, 3, 4, 5, 6, 7, 8, 9" let input3 = ["No comma"] input3 |> String.concat "," // evaluates "No comma"
StdErrRequires & types
Requires: open Axial.Process; open Axial.Process.DSL (packages: Axial.Process)val errors: Flow<ProcessHostEnvironment,ProcessError,(string list * ProcessCompletion)>val errorLines: string listval errorCompletion: ProcessCompletionval outputs: Flow<ProcessHostEnvironment,ProcessError,(ProcessOutput list * ProcessCompletion)>val events: ProcessOutput listval allStdout: boolval original: OutputChannel -> stringLimit lines and choose ordinary stream APIs explicitly
The limit counts decoded UTF-16 code units, excluding line delimiters. maxLineLength is independent of
byte-tail capture: limiting retained output does not make an oversized observed line acceptable.
let oversized =
cmd $"printf abcde" |> maxLineLength 4 |> streamStdoutLines |> ProcessStream.runDrain
match oversized |> Process.tryRun with
| Exit.Failure(Cause.Fail(ProcessError.LineTooLong _)) -> ()
| other -> failwithf "Expected line limit failure, got %A" other
let ordinary =
cmd $"printf 'a\nb\n'" |> streamStdoutLines |> ProcessStream.toFlowStream
|> FlowStream.map _.ToUpperInvariant() |> FlowStream.runCollect
ordinary |> Process.run |> shouldEqual ["A"; "B"]
oversized: Flow<ProcessHostEnvironment,ProcessError,ProcessCompletion>cmd: FormattableString -> ProcessCommand(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
maxLineLength: int -> ^a -> ProcessSpecstreamStdoutLines: ^a -> ProcessStream<'b,string>Axial.Process.ProcessStreamrunDrain: ProcessStream<'a,'b> -> Flow<'a,ProcessError,ProcessCompletion>Consumes selected output without accumulating values and returns completion.
Axial.Process.ProcesstryRun: ^source -> ^resultRuns with live services and returns Exit, including typed failures and interruptions.
Axial.Exit`2Represents the final outcome of a workflow execution. The type of the success value. The type of the domain-specific failure value.
FailureThe workflow failed due to a specific cause.
Axial.Cause`1Represents the cause of a failed workflow. The type of the domain-specific failure value.
FailAn expected domain-specific failure.
Axial.Process.ProcessErrorExpected process errors. Runtime cancellation remains Cause.Interrupt.
LineTooLongother: Exit<ProcessCompletion,ProcessError>failwithf: Printf.StringFormat<'T,'Result> -> 'TPrint to a string buffer and raise an exception with the given result. Helper printers must return strings. The formatter. The formatted result. See Printf.failwithf (link: ) for examples.
ordinary: Flow<ProcessHostEnvironment,ProcessError,string list>toFlowStream: ProcessStream<'a,'b> -> FlowStream<'a,ProcessError,'b>Converts to ordinary FlowStream, discarding successful process completion.
Axial.FlowStreamModulemap: ('v -> 'w) -> FlowStream<'env,'error,'v> -> FlowStream<'env,'error,'w>Transforms the successful values of a stream using the provided function. The function to transform each value. The stream whose values should be transformed. A new stream that yields transformed values. let stream = FlowStream.fromSeq [1; 2; 3] |> FlowStream.map (fun n -> n * 2)
_arg1: stringToUpperInvariant: unit -> stringReturns a copy of this object converted to uppercase using the casing rules of the invariant culture. The uppercase equivalent of the current string.
runCollect: FlowStream<'a,'b,'c> -> Flow<'a,'b,'c list>Collects all emitted values into a list. stream |> FlowStream.runCollect
run: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
shouldEqual: 'a -> 'a -> unitRequires & types
Requires: open Axial; open Axial.Process; open Axial.Process.DSL (packages: Axial, Axial.Process)val oversized: Flow<ProcessHostEnvironment,ProcessError,ProcessCompletion>val ordinary: Flow<ProcessHostEnvironment,ProcessError,string list>streamStdout and streamStderr provide metadata-bearing decoded chunks when line framing is inappropriate.
framing OutputFraming.Lines selects line framing for metadata-bearing observations, while the explicit
stream*Lines constructors select it for you. overallTimeout covers completion-aware callbacks; timeout
on a command ends at that stage's native exit. Use drainTimeout for lingering redirected I/O after all stages exit.

