Монадный преобразователь для понимания

#scala #monad-transformers #for-comprehension

#scala #монадные трансформаторы #для понимания

Вопрос:

Рассмотрим:

 def xs(c: String): Option[List[Long]] = ...

val ys: Stream[Long] = ...
 

Теперь я бы написал метод что-то вроде:

 def method(oc: Option[String]): Option[Long] = for { 
    c <- oc
    list <- xs(c)
} yield{        
    for {
        first <- ys.find(list contains _)
    } yield first
}
 

но, конечно, это не компилируется, поскольку предполагаемый тип — Option[Option[Long]] .

Есть ли способ с точки зрения синтаксиса scala и стандартной библиотеки получить опцию [Long]? Я знаю, что могу сопоставить шаблон, но вопрос, можно ли это сделать, используя для понимания, только что возник.


Спасибо tenshi за ответ, который выполняет свою работу, однако я только что столкнулся с другим примером моей проблемы:

 class T
class U
class A(t: String)(implicit x: T)
def getU(a: A): Option[U] = ...

def getU_2(oc: Option[String]): Option[U] = for{
   c <- oc
} yield{
   implicit val someImplicit: T = new T
   val a = A(c)

   getU(a)
}
 

Я могу добавить a в for as: a <- Some(A(c)) но как насчет неявного? Должно ли это означать изменение дизайна в моем коде?

Комментарии:

1. Не уверен в ваших намерениях, но у вас есть синтаксическая ошибка 2. Вы забыли for ключевое слово в начале тела метода, и вам следует использовать <- in first = ys.find(list contains _) .

2. Спасибо за ответ и комментарий, я обновил вопрос.

3. Ну, я думаю, мне уже слишком поздно кодировать или просто слишком взволнован написанием в функциональном стиле :), это исправило это: def getU_2(oc: Option[String]): Option[U] = { implicit .. for { c <- oc a <- Some(A(c)) u <- getU(a) } yield u }

Ответ №1:

Почему вы используете 2 вложенных for понимания? Разве не следует выполнять эту работу?

 def method(oc: Option[String]): Option[Long] = 
    for { 
        c <- oc
        list <- xs(c)
        first <- ys.find(list contains _)
    } yield first 
 

Обновить

О вашем втором примере. Вы можете определить implicit в другом месте и импортировать его или определить его в начале метода, но я предполагаю, что вы хотите сделать его область действия как можно более узкой. В этом случае вы можете использовать block непосредственно в for понимании:

 def getU_2(oc: Option[String]): Option[U] = for {
   c <- oc
   a <- {
       implicit val someImplicit: T = new T
       getU(new A(c))
   }
} yield a
 

или (вероятно, самый простой) явно укажите неявный параметр:

 def getU_2(oc: Option[String]): Option[U] = for {
   c <- oc
   a <- getU(new A(c)(new T))
} yield a