Motoko Result Error propagation

In the following Motoko code, each action has the same error type “MyErr”. How do we run all actions and if any that fails returns its error?

func some(x:Action) : Result<(), MyErr> {

let #ok(resp) = action1(x) else return #err( _ ) // Won't work

switch(action1(x)) {
   case (#ok()) ();
   case (#err(e) return #err(e);
} // This works, but a lot of code is added, and having
//  many actions it's not pretty anymore

switch(action2(x)) {
   case (#ok()) ();
   case (#err(e) return #err(e);
} 

}

There is also this approach we use in Rechain

    public func dispatch(action : A) : ({ #Ok : BlockId; #Err : E }) {
      let reducerResponse = Array.map<ActionReducer<A, E>, ReducerResponse<E>>(reducers, func(fn) = fn(action));
      let hasError = Array.find<ReducerResponse<E>>(reducerResponse, func(resp) = switch (resp) { case (#Err(_)) true; case (_) false });

      switch (hasError) { case (? #Err(e)) { return #Err(e) }; case (_) () };
      
      ignore Array.map<ReducerResponse<E>, ()>(reducerResponse, func(resp) { let #Ok(f) = resp else return (); f(blockId) });

Where each action returns Error or a function that should be executed if there are no errors at all.

action(x:Nat) : Result<() -> (), MyErr>

There are also these Result methods I haven’t seen examples of and may come in handy.

Perhaps this is the solution

func some(x:Action) : Result<(), MyErr> {

all_or_none([
func () = action1(x,y,z),
func () = action2(x),
//...
}

But would that cost too much instructions coming from the anonymous functions and the array?
Where all_or_none runs all actions, checks if there are errors, and if not executes the functions. Or run_until_first_err that returns the first error similar to the first example

1 Like