2

私の例ではOptions を使用しますが、実際のコードではカスタム データ型を使用していました。インポートを追加するimport cats.std.option._と、例の問題が解決されます。次のようなコードがありました。

import cats.{FlatMap, Eval, Applicative}
import cats.data.Kleisli
import cats.syntax.all._

implicit val optionApplicative = new Applicative[Option] {
  override def pure[A](x: A): Option[A] = Option(x)
  override def ap[A, B](fa: Option[A])(f: Option[(A) => B]): Option[B] = for {
    a <- fa
    fUnwrapped <- f
  } yield fUnwrapped(a)
}

val test : Option[(Int, String)] = (Option(4) |@| Option("name")).map((_, _))

このコードは問題なくコンパイルおよび実行されました。

次に、以下Kleisliを返すいくつかの関数を構成していましたOption

val test2 : List[Int] => Option[Int] = {
  val f = (xs : List[Int]) => xs.headOption
  val g = (x : Int) => Option(x)
  Kleisli(f).andThen(g).run
}

FlatMapデータ型にインスタンスがないため、コードはコンパイルされませんでした。私はそれを作成しました:

implicit val optionFlatmap = new FlatMap[Option] {
  override def flatMap[A, B](fa: Option[A])(f: (A) => Option[B]): Option[B] = fa.flatMap(f)
  override def map[A, B](fa: Option[A])(f: (A) => B): Option[B] = fa.map(f)
}

インスタンスをインポートFlatMap(または同じファイルで定義) すると、ビルダーの構文がコンパイルされなくなります。エラーが発生します:

error: value |@| is not a member of Option[Int]
[ERROR]   val test : Option[(Int, String)] = (Option(4) |@| Option("name")).map((_, _))
[ERROR]                                                 ^

FlatMapインスタンスをインポートするとビルダー構文が壊れるのはなぜですか? どうすればこれを修正できますか?

4

1 に答える 1

5

コンパイラ フラグを使用してこれをデバッグすると便利です。-Xlog-implicitsコンパイラ フラグは、コンパイラが試行した暗黙関数と、失敗した理由を示します。あなたの場合、最初のメッセージ(少なくとも私にとっては)がそれを説明しています:

scala> (Option(4) |@| Option("name")).map((_, _))
<console>:20: applySyntax is not a valid implicit value for Option[Int] => ?{def |@|: ?} because:
ambiguous implicit values:
 both value optionApplicative of type => cats.Applicative[Option]
 and value optionFlatmap of type => cats.FlatMap[Option]
 match expected type cats.Apply[Option]
       (Option(4) |@| Option("name")).map((_, _))

適用操作が機能するには、暗黙的Apply[Option]が必要ですが、両方ApplicativeFlatMapextendsApplyがあるため、コンパイラはどちらを選択するかわかりません。これに対する簡単な解決策は、両方のインスタンスを のインスタンスに結合し、 と の両方をMonad拡張することです。ApplicativeFlatMap

import cats._
import cats.data.Kleisli
import cats.syntax.all._

implicit val optionMonad = new Monad[Option] {

  def pure[A](x: A): Option[A] = Option(x)

  def flatMap[A, B](fa: Option[A])(f: (A) => Option[B]): Option[B] = fa.flatMap(f)

}

今、すべてが動作します:

scala> val test : Option[(Int, String)] = (Option(4) |@| Option("name")).map((_, _))
test: Option[(Int, String)] = Some((4,name))

scala> val test2 : List[Int] => Option[Int] = {
  val f = (xs : List[Int]) => xs.headOption
  val g = (x : Int) => Option(x)
  Kleisli(f).andThen(g).run
}

test2: List[Int] => Option[Int] = <function1>
于 2015-12-20T00:33:02.300 に答える