Scala для понимания с Option и Some, завернутый в ReaderT - PullRequest
2 голосов
/ 25 марта 2019

Вот пример, который отлично работает:

  import cats.data.ReaderT
  import cats.instances.option._
  ...
  def f1:ReaderT[Option, Service, Int] =
    ReaderT(service => for {
      res <- Some(10)
    } yield res )

Вот пример, который не скомпилирован:

  def f2:ReaderT[Option, Service, Int] =
    for {
      res <- ReaderT((_:Service) => Some(10))
    } yield res

Я получаю следующую ошибку:

Ошибка: (53, 11) не удалось найти неявное значение для параметра F: cats.Functor [Some] res <- ReaderT ((<em>: Service) => Some (10)) Ошибка: (53, 11) недостаточно аргументов для отображения метода: (неявный F: cats.Functor [Some]) cats.data.Kleisli [Some, com.savdev.Service, Int].Неуказанное значение параметра F. res <- ReaderT ((</em>: Service) => Some (10))

Чтобы исправить ошибку во 2-м примере, я должен вернуть не Some,но Option, который является родителем для Some:

  def f2:ReaderT[Option, Service, Int] =
    for {
      res <- ReaderT((_:Service) => Option(10))
    } yield res

Не могли бы вы объяснить это?Почему в первом примере возвращение Some, а не Option, работает нормально.Почему при этом во 2-м примере возвращение Some не компилируется?Есть ли возможность компиляции случаев компилятором Scala, как во втором примере?Или другое решение.

Ответы [ 2 ]

4 голосов
/ 25 марта 2019
  1. В первом случае он вызывает map непосредственно для Some, который, как известно, возвращает Option (обычный полиморфизм с подклассом Some из Option), затем онпродолжает поиск Functor[Option].

  2. Во втором случае тип возвращаемой функции вашей функции выводится как Some[Int], и компилятор пытается найти экземпляр Functor[Some] класс типов для вызова метода на Reader (специальный полиморфизм с классом типов Functor), но это не удается, потому что для Some.

нет функтора.Основная проблема заключается в том, что Some - это не просто конструктор экземпляров типа Option (как это было бы, например, в Haskell), но на самом деле это конструктор экземпляров типа (в основном бесполезный) Some., что иногда портит вывод типа / подразумевает разрешение.

Если вы хотите принудительно установить, что результирующий тип равен Option[Int], используйте Option(10) для построения Some или Option.empty для построения None.

3 голосов
/ 25 марта 2019

Попробуйте

import cats.syntax.option._

def f2: ReaderT[Option, Service, Int] =
  for {
    res <- ReaderT((_: Service) => 10.some)
  } yield res

Лучше использовать x.some и none (или none[X]) вместо Some(x) и None. Они имеют тип Option[X] вместо Some[X] и None.type. Это может иногда улучшить вывод типа. На самом деле это Option, который является экземпляром Functor, а не Some.

Посмотрите на "Конструкторы метода расширения" в https://blog.softwaremill.com/9-tips-about-using-cats-in-scala-you-might-want-to-know-e1bafd365f88

В первом случае вам просто повезло, что типы были выведены правильно.

...