Scala GADT 实例 Functor
Scala GADT instance Functor
在 Haskell 我得到了:
data Foo a where
Bar :: a -> Foo a
Map :: (a -> b) -> Foo a -> Foo b
instance Functor Foo where
fmap = Map
在 Scala 中我想到了:
import cats.Functor
trait Foo[A]
case class Bar[A](t: A) extends Foo[A]
case class Map[A,B](fun: A => B,foo: Foo[A]) extends Foo[B]
implicit val fooFunctor: Functor[Foo] = new Functor[Foo] {
def map[A,B](fa: Foo[A])(f: A => B) = Map(f,fa)
}
但是 Bar(40).map(_+2)
给我:
error: value map is not a member of Bar[Int]
我是 Scala 的新手,不太了解继承方式。
我错过了什么?
您需要将 Bar(40)
明确地向上转换为 Foo
,并导入隐式语法:
import cats.syntax.functor._
(Bar(40): Foo[Int]).map(_+2)
你需要向上转换,因为 Scala 会为表达式 Bar(40)
推断类型 Bar[Int]
,然后这会干扰找到添加 map
方法的适当隐式。出于这个原因,您有时会在伴随对象中看到辅助方法来为您进行向上转换:
object Foo {
def bar[A](a: A): Foo[A] = Bar(a)
// etc.
}
我想了一下如何解决这个问题。基本上,即使只有超类型是仿函数,我们也想提供仿函数操作。似乎无法表达,某些更高种类的类型是另一个类型的超类型,例如这样的事情是不可能的:def bla[F[_], R[_] <: F]
然而,我们可以提供从 R[] 到 F[] 的隐式转换以及 B:
的函子
abstract class ProvidesFor[R,F[_],FF[_[_]],A](val value: FF[F]) {
def convert(r: R): F[A]
}
implicit def providesFunctorForBar[A] =
new ProvidesFor[Bar[A],Foo,Functor,A](Functor[Foo]) {
override def convert(r: Bar[A]): Foo[A] = r
}
所以隐含的 val 将为我们提供一个 Foo 的仿函数以及从 Bar 到 Foo 的转换。
现在我们可以像这样提供到 Functor.Ops 的隐式转换:
implicit class FunctorOps[R[_],F[_],A](target: R[A])(implicit tc: ProvidesFor[R[A],F,Functor,A])
extends Functor.Ops[F,A] {
override val self = tc.convert(target)
override val typeClassInstance = tc.value
override def map[B](f: A => B): F[B] = typeClassInstance.map(self)(f)
override def imap[B](f: A => B)(g: B => A): F[B] = map(f)
}
现在这按预期工作了:
Bar(1).imap(_+2)(_+5)
我们也可以对地图做同样的事情:
implicit def providesFunctorForMap[A,B] =
new ProvidesFor[Map[A,B],Foo,Functor,B](Functor[Foo]) {
override def convert(r: Map[A,B]): Foo[B] = r
}
Map((_:Int) + 1,Bar(5)).map(_+2)
由于某些奇怪的原因,我在扩展 Functor.Ops 时不得不实现 map 和 imap,即使这些方法不是抽象的。事实上,当我不实现它们时它编译得很好,但它在运行时因 AbstractMethodError 而失败。因此,编译器以某种方式认为实现存在,但实际上并不存在。我怀疑他们正在使用某种删除这些实现的字节码优化工具。
在 Haskell 我得到了:
data Foo a where
Bar :: a -> Foo a
Map :: (a -> b) -> Foo a -> Foo b
instance Functor Foo where
fmap = Map
在 Scala 中我想到了:
import cats.Functor
trait Foo[A]
case class Bar[A](t: A) extends Foo[A]
case class Map[A,B](fun: A => B,foo: Foo[A]) extends Foo[B]
implicit val fooFunctor: Functor[Foo] = new Functor[Foo] {
def map[A,B](fa: Foo[A])(f: A => B) = Map(f,fa)
}
但是 Bar(40).map(_+2)
给我:
error: value map is not a member of Bar[Int]
我是 Scala 的新手,不太了解继承方式。
我错过了什么?
您需要将 Bar(40)
明确地向上转换为 Foo
,并导入隐式语法:
import cats.syntax.functor._
(Bar(40): Foo[Int]).map(_+2)
你需要向上转换,因为 Scala 会为表达式 Bar(40)
推断类型 Bar[Int]
,然后这会干扰找到添加 map
方法的适当隐式。出于这个原因,您有时会在伴随对象中看到辅助方法来为您进行向上转换:
object Foo {
def bar[A](a: A): Foo[A] = Bar(a)
// etc.
}
我想了一下如何解决这个问题。基本上,即使只有超类型是仿函数,我们也想提供仿函数操作。似乎无法表达,某些更高种类的类型是另一个类型的超类型,例如这样的事情是不可能的:def bla[F[_], R[_] <: F]
然而,我们可以提供从 R[] 到 F[] 的隐式转换以及 B:
的函子abstract class ProvidesFor[R,F[_],FF[_[_]],A](val value: FF[F]) {
def convert(r: R): F[A]
}
implicit def providesFunctorForBar[A] =
new ProvidesFor[Bar[A],Foo,Functor,A](Functor[Foo]) {
override def convert(r: Bar[A]): Foo[A] = r
}
所以隐含的 val 将为我们提供一个 Foo 的仿函数以及从 Bar 到 Foo 的转换。
现在我们可以像这样提供到 Functor.Ops 的隐式转换:
implicit class FunctorOps[R[_],F[_],A](target: R[A])(implicit tc: ProvidesFor[R[A],F,Functor,A])
extends Functor.Ops[F,A] {
override val self = tc.convert(target)
override val typeClassInstance = tc.value
override def map[B](f: A => B): F[B] = typeClassInstance.map(self)(f)
override def imap[B](f: A => B)(g: B => A): F[B] = map(f)
}
现在这按预期工作了:
Bar(1).imap(_+2)(_+5)
我们也可以对地图做同样的事情:
implicit def providesFunctorForMap[A,B] =
new ProvidesFor[Map[A,B],Foo,Functor,B](Functor[Foo]) {
override def convert(r: Map[A,B]): Foo[B] = r
}
Map((_:Int) + 1,Bar(5)).map(_+2)
由于某些奇怪的原因,我在扩展 Functor.Ops 时不得不实现 map 和 imap,即使这些方法不是抽象的。事实上,当我不实现它们时它编译得很好,但它在运行时因 AbstractMethodError 而失败。因此,编译器以某种方式认为实现存在,但实际上并不存在。我怀疑他们正在使用某种删除这些实现的字节码优化工具。