EitherT with Reader推广阅读器输入

时间:2013-12-20 01:36:04

标签: scalaz

我的代码中的标准构造是一个返回Reader [X,\ / [A,B]]的函数,我想在for comprehension中使用Either部分,所以我一直在尝试编写一个函数这将转换函数(X)=> \ / [A,B]进入EitherT [Reader [X,\ / [A,B]],A,B]。

我可以使用X的预定类型执行此操作。例如:

  case class Config(host: String)

  type ReaderConfig[C] = Reader[Config, C]

  type EitherReaderConfig[A,B] = EitherT[ReaderConfig, A,B]

  def eitherReaderF[A,B](f: Config => \/[A,B]) : EitherReaderConfig[A,B] = EitherT[ReaderConfig, A,B](Reader[Config, \/[A,B]](f))

  eitherReaderF(c => \/-(c.host)).run(Config("hostname"))

但是,我在删除Config类型和概括X时遇到问题。这是因为EitherT的第一个参数在它的类型构造中期望一个参数:F [_],但是Reader被定义为包含2:Reader [A, B]

我的一个尝试是使用类型lambdas定义一个EitherT类型。

  type EitherReaderM[X,A,B] = EitherT[({type λ[α] = Reader[X, α]})#λ, A,B]

  def eitherReaderM[X,A,B](f: X => \/[A,B]): EitherReaderM[X,A,B] = EitherT[({type λ[α] = Reader[X, α]})#λ, A,B](Reader(f))

  val r: EitherReaderM[Config, Int, String] = eitherReaderM((c: Config) => \/-(c.host))

  val run = r.run /// type returns scalaz.Kleisli[[+X]X,Config,scalaz.\/[Int,String]]

  run.apply(Config("host")) // fails: value apply is not a member of scalaz.Kleisli[[+X]X,Config,scalaz.\/[Int,String]]

最后一点失败了。我觉得我离这儿很近......

我还不完全确定发生了什么,但我可以通过2次调用来运行它。一个在EitherT上,然后一个在Kleisli上(我不确定它在哪里)。

  run.run(Config("host"))

但是,即使它在控制台中运行,它实际上也不会编译。编译时收到此错误:

种类的参数([α] scalaz.Kleisli [[+ X] X,X,α],A,B) 不符合预期种类的参数(类型F,类型A,类型B)。 [α] scalaz.Kleisli [[+ X] X,X,α]的类型参数与F类的预期参数不匹配: 类型α是不变的,但类型_被声明为协变

[ERROR] def或者读者M [X,A,B](f:X => / [A,B]):EitherReaderM [X,A,B] = EitherT({typeλ[α] = Reader [ X,α]})#λ,A,B

1 个答案:

答案 0 :(得分:0)

在这里,我们拥有它,最终的编译版本。我觉得它可以简化一点,但那是在不同的一天。

  type EitherReader[X,A,B] = EitherT[({type λ[+α] = Reader[X, α]})#λ, A,B]

  def eitherReader[X,A,B](f: X => \/[A,B]): EitherReader[X,A,B] = EitherT[({type λ[+α] = Reader[X, α]})#λ, A,B](Reader(f))

允许我用读者[X,A,B]替换Reader [X,A / B] .apply。

旧:

  def getSub(id: Int) = Reader[Config, String \/ Sub](config => config.findSub(id).right)

新:

  def getSub(id: Int) = eitherReader[Config, String, Sub]](config => config.findSub(id).right)

我觉得这样做只是为了进行类型转换,这似乎很奇怪。可能意味着我忽略了一些东西。