我承认标题不是很明确:对不起。
假设我有一个理解:
for {v1<-Validation1(input)
v2<-Validation2(v1)
v3<-Validation3(v2)
} yield resultValidation1,Validation2和Validation3做了一些检查(例如“年龄>18岁”)并使用失败/成功;因此,如果有什么问题,理解失败就会失败,我就会得到结果失败的原因,否则我就会在成功部分得到预期的值。到目前为止,一切都很好,也没有什么困难。
但是,如果Validation1、Validation2、Validation3的意见符合一些规则(例如:“这个人可以投票,因为他的年龄超过18岁,他的国籍是法国国籍”),他们就会成功。我想要的是跟踪应用的规则,以便能够在最后显示它们。
这显然是日志记录的用例。但我在路上犹豫不决:
:)
谢谢你的建议
编辑4月10日
因此,假设我想计算函数:x -> 1/sqrt(x)
首先,通过检查x>0来计算sqrt(x),如果不是零,则取逆。
对于scalaz.Validation,它很简单:
val failsquareroot= "Can't take squareroot of negative number"
val successsquareroot= "Squareroot ok"
val failinverse="Can't take inverse of zero"
val successinverse= "Inverse ok"
def squareroot(x:Double)=if (x < 0) failsquareroot.fail else sqrt(x).success
def inverse(x:Double)= if (x == 0) failinverse.fail else (1/x).success
def resultat(x:Double)= for {
y <- squareroot(x)
z<-inverse(y)
} yield z现在,如果squareroot成功,我想记录字符串的成功平方,如果逆成功,我想记录字符串的执行反转,以便函数结果在成功的情况下累加这两个字符串。
我从ValidationT开始,就像YO8建议的那样:
def squareroot2(x:Double)=ValidationT[({type f[x] = Writer[String,x]})#f, String,Double](Writer(successsquareroot,squareroot(x)))
def inverse2(x:Double)=ValidationT[({type f[x] = Writer[String,x]})#f, String,Double](Writer(successinverse,inverse(x))) 但我想不出如何把它们结合在一起。此外,为了获得其中一个的结果,我必须编写: squareroot2(4).run.run,这似乎很奇怪,而且按照我编写的方式,即使在失败的情况下,字符串的成功也会被记录下来:
println(squareroot2(-1).run.run)打印:(Squareroot,失败(不能取负数的squareroot ))
谢谢!贝诺特
编辑4月12日
所以Yo 8建议这个片段:
def squareroot(x:Double) = if (x < 0) failureT("Can't take squareroot of negative number") else successT(sqrt(x))
def inverse(x:Double) = if (x == 0) failureT("Can't take inverse of zero ") else successT(1/x)
for {
y <- squareroot(x).flatMapF(i => Writer("Squareroot ok", i))
z <- inverse(y).flatMapF(i => Writer("Inverse ok", i))
} yield z他警告我,某些类型的注释是必要的。有效地,squareroot和inverse的返回是相当丑陋的:它是一个ValidationT的东西,我有困难理解!
因此,我必须明确地指定返回类型: def逆(x: Double ):ValidationT?,E,A,其中"E“是字符串,"A”是Double(这很简单!)但是第一个呢?它必须是一个单曲(据我理解),并且我选择了最简单的Id (也就是标识)。
所以现在我们有:
def squareroot(x:Double):ValidationT[Id,String,Double]=if (x < 0) failureT(failsquareroot) else successT(sqrt(x))
def inverse(x:Double):ValidationT[Id,String,Double]=if (x == 0) failureT(failinverse)else successT(1/x) 但是,因为"y“不是一个双重的,而是一个WriterTId、String、Double,更重要的是,第一个记录的消息("Squareroot”)是“丢失”的,所以不编译。
最后,我确实喜欢上了这个:
def resultat(x:Double) = for {
y <- squareroot(x).flatMapF(i => Writer("Squareroot ok", i))
z <- inverse(y.run._2).flatMapF(i => Writer(y.run._1 + ", Inverse ok", i))
} yield z.run //Note that writing "z.run.run" doesn't compile
println("0 : " + resultat(0.0).run)
println("-1 : " +resultat(-1.0).run)
println("4 : " + resultat(4).run)这意味着:
0 : Failure(Can't take inverse of zero)
-1 : Failure(Can't take squareroot of negative number)
4 : Success((Squareroot ok, Inverse ok,0.5)凉爽的!我会更好地使用一个ListString的作家,但我认为我是好的方式!
现在,我可以想到我的假期(明天!) :)
编辑于5月14日
好吧,代码没有编译,但错误在Yo 8的最后一个建议中(请注意,这又不是冒犯,Yo8是善良的典范!)我向您提交完整的代码和错误:
import scala.math._
import scalaz._
import Scalaz._
object validlog extends ValidationTFunctions {
val failsquareroot= "Can't take squareroot of negative number"
val successsquareroot= "Squareroot ok"
val failinverse="Can't take inverse of zero"
val successinverse= "Inverse ok"
case class MyId[A]( v: A)
implicit val myIdPointed = new Pointed[MyId]{
def point[A](v: => A) = MyId(v)
}
implicit def unId[A](my: MyId[A]): A = my.v
def squareroot(x:Double):ValidationT[({type f[x] = WriterT[MyId,String, x]})#f,String,Double]=if (x < 0) failureT[({type f[x] = WriterT[MyId,String, x]})#f,String,Double](failsquareroot) else successT[({type f[x] = WriterT[MyId,String, x]})#f,String,Double](sqrt(x))
def inverse(x:Double):ValidationT[({type f[x] = WriterT[MyId, String, x]})#f,String,Double]=if (x == 0) failureT[({type f[x] = WriterT[MyId,String, x]})#f,String,Double](failinverse) else successT[({type f[x] = WriterT[MyId,String, x]})#f,String,Double](1/x)
/* def resultat(x:Double) = for {
y <- squareroot(x).flatMapF(i => Writer(", Squareroot ok", i))
z <- inverse(y).flatMapF(i => Writer(", Inverse ok", i))
} yield z */
def main(args: Array[String]): Unit = {
println(inverse(0.0).run)
println(inverse(0.5).run)
println(squareroot(-1.0).run)
println(inverse(4.0).run)
}
}这是终端的会话:
benoit@benoit-laptop:~$ cd scala
benoit@benoit-laptop:~/scala$ scala -version
Scala code runner version 2.9.2 -- Copyright 2002-2011, LAMP/EPFL
benoit@benoit-laptop:~/scala$ scala -cp ./scalaz7/scalaz-core_2.9.2-7.0-SNAPSHOT.jar validlog.scala
/home/benoit/scala/validlog.scala:15: error: object creation impossible, since method map in trait Functor of type [A, B](fa: Main.MyId[A])(f: A => B)Main.MyId[B] is not defined
implicit val myIdPointed = new Pointed[MyId]{
^
one error found我想我从一开始就错过了一些东西,可以解释为什么我会被粘上几个星期!
贝诺特
编辑于5月15日
编译您的代码时,我有第一个错误:
could not find implicit value for parameter F: scalaz.Pointed[Main.$anon.ValidationTExample.WriterAlias]经过几次尝试,我以这样的方式重写了导入:
import scalaz.Writer
import scalaz.std.string._
import scalaz.Id._
import scalaz.WriterT
import scalaz.ValidationT
import scala.Math._仍然有一个错误:
error: could not find implicit value for parameter F: scalaz.Monad[[x]scalaz.WriterT[[+X]X,String,x]]
y <- squareroot(x).flatMapF(i => Writer("Squareroot ok", i))
^
one error found这个错误出现在您在5月14日编写的代码中。很显然,很难理解如何准确地使用Scalaz-7导入什么。使用版本6,事情看起来更简单:只需导入scalaz._和Scalaz._
我觉得自己像一个“绝望的家庭作家”:) (是的,我同意,这不是很精明,但它是放松!)
贝诺特
5月23日
出去!它有效地适用于Scalaz-7的最后一个版本:请注意,我必须构建它,而不是下载快照。
太好了!
对于那些感兴趣的人,以下是输出:
0 : (Squareroot ok,Failure(Can't take inverse of zero ))
-1 : (,Failure(Can't take squareroot of negative number))
4 : (Squareroot ok, Inverse ok,Success(0.5))八号,如果有一天我们偶然见面,我会付你一瓶啤酒的!
贝诺特
发布于 2012-03-28 13:18:16
为了在一元计算期间进行日志记录,您必须使用Writer实例。由于monad不构成并且您希望保持“验证”效果,所以您应该使用验证Monad转换器。我不知道您使用的是哪个版本的ScalaZ,但是Scalaz7 (分支服务器-7)提供了这样的单播转换器(即ValidationT)。
所以我们得到:
ValidationT[({type f[x] = Writer[W, x]})#f, A]与你的记录器的类型
根据您的编辑,下面是我要做的
def squareroot(x:Double) = if (x < 0) failureT("Can't take squareroot of negative number") else successT(sqrt(x))
def inverse(x:Double) = if (x == 0) failureT("Can't take inverse of zero ") else successT(1/x)现在,如何在理解中使用它
for {
y <- squareroot(x).flatMapF(i => Writer("Squareroot ok", i))
z <- inverse(y).flatMapF(i => Writer("Inverse ok", i))
} yield z这些片段可能需要更多的类型注释。
编辑4月13日
下面是正确的方法类型注释:
def squareroot(x:Double):ValidationT[({type f[x] = Writer[String, x]})#f,String,Double]
def inverse(x:Double):ValidationT[{type f[x] = Writer[String, x]})#f,String,Double]这样,您就可以像这样定义结果方法:
def resultat(x:Double) = for {
y <- squareroot(x).flatMapF(i => Writer(", Squareroot ok", i))
z <- inverse(y).flatMapF(i => Writer(", Inverse ok", i))
} yield z您也可以使用ListString作为日志类型,因为它是一个单类
顺便说一句,如果有帮助的话,我会说法语:-)
编辑5月14日
问题是:编译器无法解决
implicitly[Pointed[({ type f[x] = Writer[String, x] })#f]]因为WriterT需要一个MonoidString和PointedId的实例。
import std.string._ // this import all string functions and instances
import Id._ // this import all Id functions and instances以下是完整的可执行代码
import scalaz._
import std.string._
import Id._
import scalaz.WriterT
import scalaz.ValidationT
import scala.Math._
object ValidationTExample extends Application {
type ValidationTWriterAlias[W, A] = ValidationT[({type f[x] = Writer[W, x]})#f, W, A]
type WriterAlias[A] = Writer[String, A]
def squareroot(x:Double): ValidationTWriterAlias[String, Double] =
if (x < 0) ValidationT.failureT[WriterAlias, String, Double]("Can't take squareroot of negative number")
else ValidationT.successT[WriterAlias, String, Double](sqrt(x))
def inverse(x:Double): ValidationTWriterAlias[String, Double] =
if (x == 0) ValidationT.failureT[WriterAlias, String, Double]("Can't take inverse of zero ")
else ValidationT.successT[WriterAlias, String, Double](1/x)
def resultat(x:Double) = for {
y <- squareroot(x).flatMapF(i => Writer("Squareroot ok", i))
z <- inverse(y).flatMapF(i => Writer(", Inverse ok", i))
} yield z
println("0 : " + resultat(0.0).run.run)
println("-1 : " + resultat(-1.0).run.run)
println("4 : " + resultat(4).run.run)
}编辑8月14日
此代码在Scalaz-7中不再有效。ValidationT已经被删除,因为验证不是单一的。希望可以用EitherT代替。此外,还添加了一个新的MonadWriter/ListenableMonadWriter类型类库来减轻这些类型注释。
import scalaz._
import std.string._
import syntax.monadwriter._
import scala.Math._
object EitherTExample extends Application {
implicit val monadWriter = EitherT.monadWriter[Writer, String, String]
def squareroot(x: Double) =
if (x < 0)
monadWriter.left[Double]("Can't take squareroot of negative number")
else
monadWriter.right[Double](sqrt(x))
def inverse(x: Double) =
if (x == 0)
monadWriter.left[Double]("Can't take inverse of zero")
else
monadWriter.right[Double](1 / x)
def resultat(x: Double) = for {
y <- squareroot(x) :++> "Squareroot ok"
z <- inverse(y) :++> ", Inverse ok"
} yield z
println("0 : " + resultat(0.0).run.run)
println("-1 : " + resultat(-1.0).run.run)
println("4 : " + resultat(4).run.run)
}https://stackoverflow.com/questions/9896309
复制相似问题