Home > front end >  What is this concept called in Haskell?
What is this concept called in Haskell?

Time:11-03

I'm writing some relatively functional style code in C , and am trying to avoid inventing a bad name for it. To that end I'm trying to stick to the names of isomorphic concepts in Haskell where possible. (To be clear I don't know a lot of Haskell, but reading about it has been quite illuminating.)

If I've done the Haskell typing correctly, I believe the concept I'm looking for the name of would have this signature:

someName :: (Monad m1, Monad m2) => (a -> m1 b) -> (m2 a -> m1 m2 b)

The idea is that you have a function suitable for using to bind a monad of type m1, and you transform it into a function that is suitable for binding m1 values that contain m2 values.

I can't write Haskell well enough to give an example, but here is pseudo-C illustrating what I want, using std::optional and absl::StatusOr:

// A silly example of a bind function for absl::StatusOr<int>.
absl::StatusOr<int> AddTwoUnless17(int x) {
  if (x == 17) {
    return absl::InternalError("can't add two to 17!")
  }
  
  return x   2;
}

// Convert AddTwoUnless17 into a bind function for
// absl::StatusOr<std::optional<int>>. The resulting logic is:
//
//  *  If the input is an error, propagate that error.
//  *  If the input is std::nullopt, return std::nullopt.
//  *  If the input is 17, return an error.
//  *  Otherwise return the input plus two.
//
// Here we have:
//
//     m1: absl::StatusOr
//     m2: std::optional
//
std::function<absl::StatusOr<std::optional<int>>(std::optional<int>) f =
    someName(AddTwoUnless17);

CHECK_EQ(
    absl::CancelledError(),
    f(absl::StatusOr<std::optional<int>>(absl::CancelledError())));

CHECK_EQ(
    std::nullopt,
    f(absl::StatusOr<std::optional<int>>(std::nullopt)));

CHECK_EQ(
    absl::InternalError("can't add two to 17!"),
    f(absl::StatusOr<std::optional<int>>(17)));

CHECK_EQ(
    13,
    f(absl::StatusOr<std::optional<int>>(11)));

Is there a name for this concept? If not, is it because it is flawed in some way, or can be built out of simpler pieces?

CodePudding user response:

The type signature you wrote is basically the same as:

traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)

where f = m1 and t = m2.

But it doesn't always work if m2 is an arbitrary monad. It must be Traversable.

  • Related