我承认标题不是很明确:对此表示抱歉。

假设我有一个理解力:

for {v1<-Validation1(input)
     v2<-Validation2(v1)
     v3<-Validation3(v2)
} yield result

Validation1,Validation2和Validation3进行了一些检查(例如“年龄> 18”),并使用失败/成功;因此,如果出现问题,那么理解就会中止,我会在失败的结果部分得到原因,否则我会在成功的部分得到期望值。到目前为止,一切都很好,没有什么困难。

但是,如果Validation1,Validation2,Validation3的输入满足某些规则(例如,“该人可以投票,因为他的年龄大于18岁并且他的国籍是法国人”,则可以成功)。我要跟踪的是所应用的规则,以便能够在最后显示它们。

显然,这是日志记录的用例。但我对这样做的方式犹豫不决:
  • 有一个对象“logger”,可以通过任何功能(Validation1、2和3,但也要显示日志内容的调用方)访问该对象
  • 使记录器成为Validation1、2和3的参数
  • 等待“Scala中的功能编程”的相关章节:)
  • 其他吗?

  • 感谢您的建议

    于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
    

    现在,如果平方根成功,我想记录字符串successsquaretoot,如果成功,则想记录字符串successinverse,这样在成功的情况下,函数resultat会同时存储两个字符串

    我是从ValidationT开始的,因为Yo Three建议:
     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
    这似乎很奇怪
    并且以我写的方式,即使失败,也会记录字符串successsquareroot:
     println(squareroot2(-1).run.run)
    

    打印:(平方根好,失败(不能取负数的平方根))

    谢谢!
    贝诺伊特

    于4月12日编辑

    因此Yo Yo建议使用以下代码段:
     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
    

    他警告我,一些类型注释是必要的。实际上,平方根和逆的返回tpye相当丑陋:这是我难以理解的东西的ValidationT!

    因此,我必须明确指定返回类型:def inverse(x:Double):ValidationT [?,E,A]其中“E”是字符串,“A”是Double(这很简单!)。但是第一个呢?它必须是monad(据我所知),我选择了最简单的ID:Id(即Identity)。

    现在我们有了:
       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”不是Double而是WriterT [Id,String,Double]
    此外,第一个记录的消息(“Squareroot ok”)为“丢失”。

    最终,我做到了:
       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)
    

    凉爽的!我最好为Writer使用List [String],但我认为我做的很好!

    现在,我可以考虑我的假期了(明天!):)

    于5月14日编辑

    好的,代码不会编译,但是错误是Yo八的最后一个建议(请注意,Your八是善良的典范,这也不是冒犯!)。我向您提交完整的代码和错误:
    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)
      }
    
    
    
    }
    

    这是终端的 session :
    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-seven准确导入什么。使用版本6,事情看起来更简单:只需导入scalaz._和Scalaz._

    我觉得自己像个“绝望的作家”:)(是的,我同意,虽然不是很精巧,但是很放松!)

    贝诺伊特

    5月23日

    uf!它与scalaz-seven的最新版本有效地工作:请注意,我必须构建它而不是下载快照。

    那太棒了!

    对于那些感兴趣的人,这里是输出:
     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))
    

    八岁,如果碰巧我们有一天见面,我给你付啤酒!

    贝诺伊特

    最佳答案

    为了在单子(monad)计算期间进行记录,您必须使用Writer monad的实例。由于monad无法合成,并且您想保持“Validation”效果,因此您应该使用Validation Monad Transformer。我不知道您正在使用哪个版本的ScalaZ,但是Scalaz7(分支scalaz-seven)提供了这种monad转换器(即ValidationT)。

    这样我们得到:

    ValidationT[({type f[x] = Writer[W, x]})#f, A]
    

    带W的记录器类型

    根据您的编辑,这是我的操作方法
    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]
    

    这样,您可以定义resultat方法,如下所示:
    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
    

    您还可以将List [String]用作日志类型,因为它是类半身像

    顺便说一句,我会说法语,如果可以的话:-)

    于5月14日进行编辑

    问题是:编译器无法解决
    implicitly[Pointed[({ type f[x] = Writer[String, x] })#f]]
    

    因为WriterT需要Monoid [String]和Pointed [Id]的实例。
    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-seven中不再有效。由于Validation不是monad,因此已删除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)
    }
    

    关于validation - Scalaz : validating in a for-comprehension and logging,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9896309/

    10-11 19:20