How can I use flatMap a Try [Option] in an idiomatic key

I want flatMap a Try [Option [A]] to use some function that uses the value inside Option to create another Try, and I want the solution to be simple and idiomatic. I have illustrated a problem with an example. The goal is to create an Option [Group] with members and events enclosed in one Try, which may contain errors from any of the three functions.

def getGroup(id: Long): Try[Option[Group]]

def getMembersForGroup(groupId: Long): Try[Seq[Member]]

def getMeetingsForGroup(groupId: Long): Try[Seq[Meeting]]

I find it difficult to map FlatMap to Try returned getGroupin Try from member-and meeting functions, because there is an option "on this way". This is what I came up with:

getGroup(id).flatMap(
  groupOpt => groupOpt.map(
    group => addStuff(group).map(group => Some(group))
  ).getOrElse(Success(None))
)

def addStuff(g: Group): Try[Group] =
  for {
    members <- getMembersForGroup(g.id)
    meetings <- getMeetingsForGroup(g.id)
  } yield g.copy(members = members, meetings = meetings)

, , , addStuff Option getOrElse. - Option [Try [Option [Group]]], , , .

?

+4
4

OptionT, : .

:

def getGroupWithStuff(id: Long): OptionT[Try, Group] = {
  for {
    g <- OptionT(getGroup(id))
    members <- OptionT.liftF(getMembersForGroup(g.id))
    meetings <- OptionT.liftF(getMeetingsForGroup(g.id))
  } yield g.copy(members = members, meetings = meetings)
}
+3

.fold .map.getOrElse... :

 getGroup(id)
   .flatMap { 
     _.fold(Try(Option.empty[Group])){ 
       addStuff(_).map(Option.apply) 
     }
   }

- , :

  getGroup(id).flatMap {
    case None => Success(None)
    case Some(group) => addStuff(group).map(Option.apply)
  }
+1

, getGroup:

  getGroup(id).map(
    groupOpt => groupOpt.flatMap(
      group => addStuff(group).toOption
    )
  )

addStuff. , , .

0

. , , ( , ).

def getFullGroup(id: Long): Try[Option[Group]] =
  getGroup(id).flatMap[Option[Group]] { _.map[Try[Group]]{ group =>
    for {
      meetings <- getMeetingsForGroup(id)
      members  <- getMembersForGroup
    } yield group.copy(meetings = meetings, members = members)
  }.fold[Try[Option[Group]]](Success(None))(_.map(Some(_)))
}

:

fold[Try[Option[Group]]](Success(None))(_.map(Some(_)))

IDE. , , , , , . , , .

OptionT Try[Option[Group]] - OptionT[Try, Group]. , :

def getFullGroup(id: Long): OptionT[Try, Group] =
  OptionT(getGroup(id)).flatMapF { group =>
    for {
      meetings <- getMeetingsForGroup(id)
      members  <- getMembersForGroup(id)
    } yield group.copy(meetings = meetings, members = members)
  }
}

. , .

, , Try Option, sequence. , traverse. , . OptionT - :

def getFullGroup(id: Long): Try[Option[Group]] =
  getGroup(id).flatMap[Option[Group]] { _.traverse { group =>
    for {
      meetings <- getMeetingsForGroup(id)
      members  <- getMembersForGroup
    } yield group.copy(meetings = meetings, members = members)
  }
}

( , f, , f.)

0

Source: https://habr.com/ru/post/1690710/


All Articles