spebbe / dartz

Functional programming in Dart
MIT License
749 stars 60 forks source link

Question how to access Either Left / Right without fold #66

Closed fionues closed 3 years ago

fionues commented 3 years ago

Is there a way to access Left and Right without using fold?

Context: I am in a loop and if I get a Left result i want to return but if i get a Right result i want to add it to a list. So i cant use fold().

List wallets = [];

for(Wallet libWallet in libWallets.items){
  final walletProfiles = await profiles(
              libWallet.category == WalletCategory.company,
              forWalletId: libWallet.walletID);

     if(walletProfiles.isLeft()){
           // is something like this possible?
            return walletProfiles.left;
     }

     if(walletProfiles.isRight()){
           // is something like this possible?
            wallets.add(walletProfiles.right);
      }
};
spebbe commented 3 years ago

Hi @fionues!

If you just want to perform a side effect on Right values, use forEach, like this:

walletProfiles.forEach(wallets.add);

If you want the early return in your example above and want to keep the imperative style, just use type casing in the loop:

if (walletProfiles is Right<SomeFailureType, SomeSuccessType>) {
  wallets.add(walletProfiles.value);
} else {
  return whateverYouWantToReturn;
}

If you want to move more towards an FP style, you could instead replace the whole loop with something like this:

return IList.sequenceEither(await ilist(libWallets.items)
  .traverseFuture((libWallet) =>
    profiles(libWallet.category == WalletCategory.company, forWalletId: libWallet.walletID)));

I don't know your whole program or all the types, but the return value should then be of type Either<YourFailureType, IList<WhateverProfilesReturns>>.

Hope that helped!

fionues commented 3 years ago

ah thank you very much. a lot of good options. I would like to stick to the imperative style since I am not yet familiar enough with the FP style.

If I understood correctly then the walletProfiles.value holds either the Right oder the Left value? So i can return the Left value after a is Right / is Left check? like this:

if (walletProfiles is Right<SomeFailureType, SomeSuccessType>) {
  wallets.add(walletProfiles.value);
} else {
// returns value of SomeFailureType?
  return walletProfiles.value;
}
if (walletProfiles.isLeft()) {
  // returns value of SomeFailureType?
  return walletProfiles.value;
} 
spebbe commented 3 years ago

Almost! value is individually defined (not inherited) on both Left and Right, returning L and R respectively. Therefore you need to type case in order to access value. Checking isRight()/isLeft() is not enough to convince the type system. This is annoying but intentional, since otherwise the point of Either (~reminding you of potential error cases) would be completely lost.

The long boring version then looks like this:

if (walletProfiles is Right<SomeFailureType, SomeSuccessType>) {
  wallets.add(walletProfiles.value);
} else if (walletProfiles is Left<SomeFailureType, SomeSuccessType>)  {
  return walletProfiles.value;
}

While not very pretty, you can avoid the second silly type case by doing something like this:

if (walletProfiles is Right<SomeFailureType, SomeSuccessType>) {
  wallets.add(walletProfiles.value);
} else {
  return walletProfiles.swap()|null;
}