Scala中2型参数函子的正确实现
我多次看到这个问题,但无论我怎么努力,我都无法编译下面的代码。目标是为更简单的Scala中2型参数函子的正确实现,scala,intellij-idea,functional-programming,Scala,Intellij Idea,Functional Programming,我多次看到这个问题,但无论我怎么努力,我都无法编译下面的代码。目标是为更简单的读取器实现Functor实现(代码为): 我试图通过以下方式绕过隐式机制: FunctorOps(foo).fmap(_ + 1) 但这会输出以下编译错误: Error:(82, 23) type mismatch; found : com.fp.Scratchpad.Reader[String,Int] required: ?F[?A] Note that implicit conversions are
读取器实现Functor
实现(代码为):
我试图通过以下方式绕过隐式机制:
FunctorOps(foo).fmap(_ + 1)
但这会输出以下编译错误:
Error:(82, 23) type mismatch;
found : com.fp.Scratchpad.Reader[String,Int]
required: ?F[?A]
Note that implicit conversions are not applicable because they are ambiguous:
both method ArrowAssoc in object Predef of type [A](self: A)ArrowAssoc[A]
and method Ensuring in object Predef of type [A](self: A)Ensuring[A]
are possible conversion functions from com.fp.Scratchpad.Reader[String,Int] to ?F[?A]
FunctorOps(foo).fmap(_ + 1)
提前感谢您的帮助
更新
为了确保我的FunctorOps是正确的,我为Id
创建了一个functor实例:
case class Id[A](value: A)
implicit val idF: Functor[Id] = new Functor[Id] {
override def fmap[A, B](fa: Id[A])(f: A => B): Id[B] = Id(f(fa.value))
}
val id = Id(42)
id.fmap(_ + 1) // compiles
因此问题不是来自FunctorOps
隐式类。我怀疑Scala与lambdas类型的关系很不好
更新2
我试图简化问题,但没有成功:
trait Functor[F[_]] {
def map[A, B](x: F[A])(f: A => B): F[B]
}
implicit class Ops[F[_], A](fa: F[A])(implicit F: Functor[F]) {
def map[B](f: A => B): F[B] = F.map(fa)(f)
}
type FF[A] = ({ type F[B] = A => B })
implicit def ff[E]: Functor[FF[E]#F] = new Functor[FF[E]#F] {
override def map[A, B](x: E => A)(f: A => B): E => B = e => f(x(e))
}
val f: String => Int = _ => 42
val value: Functor[FF[String]#F] = ff[String]
val ops = new Ops[FF[String]#F, Int](f)(value)
// These compile
ops.map(_ + 1)("")
value.map(f)(_ + 1)("")
// This not
f.map(_ + 1)
更新:
我认为,要使其正常工作,您需要在build.sbt
中为编译器启用一些额外的选项:
scalacOptions ++= Seq(
"-Ypartial-unification",
"-language:postfixOps",
"-language:higherKinds",
"-deprecation",
"-encoding", "UTF-8",
"-feature",
"-unchecked"
)
有关部分统一标志及其解决方案的更多信息
原始答案:
您是在工作表中运行代码,还是在IDEA中进行了修改?我注意到,有时,特别是在有类型推断、隐式解析和更高级类型“魔术”的函数式编程任务中,IDEA的REPL无法完成任务(但我不确定原因)
也就是说,我试着在IDEA上运行以下内容:
object TestApp extends App{
trait Functor[F[_]] {
def fmap[A, B](fa: F[A])(f: A => B): F[B]
}
implicit class FunctorOps[F[_]: Functor, A](self: F[A]) {
def fmap[B](f: A => B): F[B] = implicitly[Functor[F]].fmap(self)(f)
}
case class Reader[A, B](run: A => B)
type ReaderF[X] = ({ type L[A] = Reader[X, A] })
implicit def readerFunctors[E]: Functor[ReaderF[E]#L] =
new Functor[ReaderF[E]#L] {
override def fmap[A, B](fa: Reader[E, A])(f: A => B): Reader[E, B] =
Reader(e => f(fa.run(e)))
}
val foo: Reader[String, Int] = Reader[String, Int](s => s.length)
val i = foo.fmap(_ + 1)
println(i.run("Test"))
println(i.run("Hello World"))
}
而且它工作良好,可以打印5
和12
。另外,正如其他人提到的,您的代码在Scastie上工作,这是IDEA行为的另一个符号
最后一点注意:您可能已经知道了这一点,但是您可以使用
长话短说,删除ReaderF[X]
type别名,并使您的functor实例如下所示:
implicit def readerFunctors[X]: Functor[Reader[X,?]] =
new Functor[Reader[X,?]] {
override def fmap[B, C](fa: Reader[X,B])(f: B => C): Reader[X,C] =
Reader(e => f(fa.run(e)))
}
IMHO哪一个更具可读性。您的Scala版本是什么?第一个是编译的。实际上,我很惊讶它似乎也能在旧版本中工作,我假设您需要2.12或2.11.11+。我刚刚检查过,Scala版本是2.12.8。试着用IDEA和sbt编译:(你是在工作表中运行这个吗?不是,我也试着编译这个原始sbtI副本,把代码粘贴到IDEA上,它甚至没有编译:(在sbt上是一样的。我在使用scala 2.12.8和sbt 1.2.8。我也试着运行这个(没有TestApp
)在标准REPL中,仍然没有成功。您使用的是什么版本?scalac还在val i=foo.fmap(+1)中发现一个错误
…这很奇怪。我使用的是普通的配置,Scala 2.12.8,没有什么特别或奇怪的…但不管怎样,我认为现在很清楚,不管问题是什么,问题不在代码中,而是在您的环境中。我想这是一个好消息:)老实说,我还是不确定。你能给我你正在使用的sbt/scala的版本吗?
implicit def readerFunctors[X]: Functor[Reader[X,?]] =
new Functor[Reader[X,?]] {
override def fmap[B, C](fa: Reader[X,B])(f: B => C): Reader[X,C] =
Reader(e => f(fa.run(e)))
}