Scala 无法在 Reader monad 实现中推断参数类型
Scala cannot infer parameter type in Reader monad implementation
我正在使用 Scala 2.13,并且正在开发我自己的 Reader
monad。 monad 的实现如下。
object ReaderMonad {
implicit def reader[From, To](f: From => To): Reader[From, To] = Reader(f)
case class Reader[From, To](f: From => To) {
def run(input: From): To =
f(input)
def map[NewTo](transformation: To => NewTo): Reader[From, NewTo] =
Reader(c => transformation(f(c)))
def flatMap[NewTo](transformation: To => Reader[From, NewTo]): Reader[From, NewTo] =
Reader(c => transformation(f(c)).run(c))
}
def pure[From, To](a: To): Reader[From, To] = Reader((c: From) => a)
}
使用这样的 monad,我正在为股票定义一个存储库。
trait StockRepository {
def findAll: Map[String, Double]
}
Stocks
服务使用存储库的实现,使用 Reader
monad 注入 repo 依赖。
object Stocks {
def findAll: Reader[StockRepository, Map[String, Double]] =
(repo: StockRepository) => repo.findAll()
}
我的问题是,为什么我要在最后一个函数定义 (repo: StockRepository) => repo.findAll()
中明确指定 repo
参数类型?为什么 Scala 编译器不能为我隐式推断类型?
非常感谢。
当然可以,你只需要删除隐式转换并添加 apply
.
但是,我添加了一些其他更改以使代码更地道且更易于使用,如果您有任何疑问,请告诉我。
object ReaderMonad {
final case class Reader[From, To] private[ReaderMonad] (run: From => To) {
def map[NewTo](transformation: To => NewTo): Reader[From, NewTo] =
Reader(c => transformation(run(c)))
def flatMap[NewTo](transformation: To => Reader[From, NewTo]): Reader[From, NewTo] =
Reader(c => transformation(run(c)).run(c))
}
// This is all you really need.
def apply[From, To](f: From => To): Reader[From, To] =
Reader(run = f)
// This is called the parially applied trick:
// https://typelevel.org/cats/guidelines.html
// It makes easier to use pure.
private[ReaderMonad] final class PurePartiallyApplied[From](private val dummy: Boolean) extends AnyVal {
@inline
final def apply[To](a: To): Reader[From, To] =
Reader(_ => a)
}
// So now, you can just:
// ReaderMonad.pure[String](10)
// Instead of:
// ReaderMonad.pure[String, Int](10)
def pure[From]: PurePartiallyApplied[From] =
new PurePartiallyApplied(dummy = true)
}
你可以这样使用它:
trait StockRepository {
def findAll: Map[String, Double]
}
object Stocks {
import ReaderMonad.Reader
def findAll: Reader[StockRepository, Map[String, Double]] =
ReaderMonad { repo =>
repo.findAll
}
}
我正在使用 Scala 2.13,并且正在开发我自己的 Reader
monad。 monad 的实现如下。
object ReaderMonad {
implicit def reader[From, To](f: From => To): Reader[From, To] = Reader(f)
case class Reader[From, To](f: From => To) {
def run(input: From): To =
f(input)
def map[NewTo](transformation: To => NewTo): Reader[From, NewTo] =
Reader(c => transformation(f(c)))
def flatMap[NewTo](transformation: To => Reader[From, NewTo]): Reader[From, NewTo] =
Reader(c => transformation(f(c)).run(c))
}
def pure[From, To](a: To): Reader[From, To] = Reader((c: From) => a)
}
使用这样的 monad,我正在为股票定义一个存储库。
trait StockRepository {
def findAll: Map[String, Double]
}
Stocks
服务使用存储库的实现,使用 Reader
monad 注入 repo 依赖。
object Stocks {
def findAll: Reader[StockRepository, Map[String, Double]] =
(repo: StockRepository) => repo.findAll()
}
我的问题是,为什么我要在最后一个函数定义 (repo: StockRepository) => repo.findAll()
中明确指定 repo
参数类型?为什么 Scala 编译器不能为我隐式推断类型?
非常感谢。
当然可以,你只需要删除隐式转换并添加 apply
.
但是,我添加了一些其他更改以使代码更地道且更易于使用,如果您有任何疑问,请告诉我。
object ReaderMonad {
final case class Reader[From, To] private[ReaderMonad] (run: From => To) {
def map[NewTo](transformation: To => NewTo): Reader[From, NewTo] =
Reader(c => transformation(run(c)))
def flatMap[NewTo](transformation: To => Reader[From, NewTo]): Reader[From, NewTo] =
Reader(c => transformation(run(c)).run(c))
}
// This is all you really need.
def apply[From, To](f: From => To): Reader[From, To] =
Reader(run = f)
// This is called the parially applied trick:
// https://typelevel.org/cats/guidelines.html
// It makes easier to use pure.
private[ReaderMonad] final class PurePartiallyApplied[From](private val dummy: Boolean) extends AnyVal {
@inline
final def apply[To](a: To): Reader[From, To] =
Reader(_ => a)
}
// So now, you can just:
// ReaderMonad.pure[String](10)
// Instead of:
// ReaderMonad.pure[String, Int](10)
def pure[From]: PurePartiallyApplied[From] =
new PurePartiallyApplied(dummy = true)
}
你可以这样使用它:
trait StockRepository {
def findAll: Map[String, Double]
}
object Stocks {
import ReaderMonad.Reader
def findAll: Reader[StockRepository, Map[String, Double]] =
ReaderMonad { repo =>
repo.findAll
}
}