2017-11-08 16 views
4

私はCats/Scalazの基本的な例を取り乱していて、チュートリアルを通って気分を味わってきました。に解決策があります。サブクラス(cats/scalaz)を使用してFunctorでジェネリック関数を呼び出す

Funerビュー(F[_] : Functor)でコンテキスト化された値(F[A])と、コンテキストが<: Fの汎用関数を呼び出すことはできますか?私はFunctorがタイプF[_]で不変であることを認識しており、Functor.widenの存在も認識していますが、一般的な関数で使用するために暗黙的に自分のタイプを広げる方法がないことは奇妙に思えます。猫で

例(Scalazと同様の例が同様に存在する):明示的にオプションのためのFunctorを召喚、もちろん

import cats.instances.all._ 
import cats.syntax.all._ 

def takesAFunctor[F[_] : cats.Functor](f: F[Int]) = f.map(_ + 1) 

takesAFunctor(Option(1)) // Works fine (of course) 
takesAFunctor(Some(1)) // No implicit for Functor[Some]. Makes sense, but can we summon one since we have a Functor[Option]? 
takesAFunctor(Some(1): Option[Int]) // Works but very verbose 

をし、マッピングが期待

Functor[Option].map(Some(1))(_ + 1) // Some(2) 

だから私の質問のように動作しますは:一般的な関数のシグネチャは、サブクラス化されたコンテキストについて説明するために変更する必要がありますか、私は知らない何らかの「暗黙の広がり」があるか、これを使ってScalaの関数型プログラミングの不幸な欠点ですstdlib?

答えて

1

Dmytroの回答が指摘しているように、これは一般的に不可能です。これは、コンストラクタを使用してSomeを返すのに対して、cat/scalazはOptionを返すようにタイプされた.some拡張メソッドを公開する理由です。

takesAFunctor(1.some)

代わりにあなたがより一般的なApply構文を使用することができます。 takesAFunctor(1.pure[Option])

私は知らない、またはこれはSTDLIBを使用してScalaで関数型プログラミングにただ残念な欠点である「暗黙の拡大」のいくつかの並べ替えはありますか?

Optionファンクタを手動で呼び出すときに表示される暗黙的な拡大は、共分散です。そのインスタンスはOptionのために不変に定義されているため、Someは受け入れられません - コンパイラは暗黙的に見つけることができませんが、Functor[Option].mapOptionまたはサブタイプOptionを期待しています。

あなたがここで言及欠点は基本的にJavaのっぽい共変サブタイプ間のインピーダンス不整合であり、よりハスケルっぽい不変型指定された型クラス

+0

A-ha!これはまさに私が探していたものでした。ありがとうございました!私は、関数の分散を考慮に入れることを完全に無視しました。それはかなり意味があります。 –

1
// No implicit for Functor[Some]. 
// Makes sense, but can we summon one since we have a Functor[Option]? 

どのように一般的なケースでは、このようなインスタンスを定義するのでしょうか? functor.map(ga)(f)は、必ずしも一般的タイプF[B]のではなくG[B]あるので

implicit def subtypeFunctor[F[_], G[T] <: F[T]](implicit functor: Functor[F]): Functor[G] = new Functor[G] { 
    override def map[A, B](ga: G[A])(f: A => B): G[B] = functor.map(ga)(f) 
    } 

は動作しません。

一般的にいいえ、サブタイプコンストラクタのファンクタを派生することは不可能であり、理由は基本的です。

FunctorFマップmap(f): F[A] => F[B](プラスいくつかの法律を)射するオブジェクトF[T]と射f: A => BTオブジェクト。 FF[B]は共変位置にあり、Fはで反反例の位置にあります。したがって、ファンクタ型クラスの唯一のオプションは型コンストラクタで不変です。

ところで、takesAFunctortakesAFunctor[Option](Some(1))と呼ぶこともできます。

+1

これは素晴らしい内訳ですが、ありがとうございました。私は、Functorが今の状況で不変である理由の背後にあるコンセプトを理解していると思います。なぜなら、私が試しているすべてがうまくいかない理由を説明するのは間違いありません。 –

関連する問題