首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Scalaz :在理解和日志记录中进行验证

Scalaz :在理解和日志记录中进行验证
EN

Stack Overflow用户
提问于 2012-03-27 19:28:09
回答 1查看 2.2K关注 0票数 9

我承认标题不是很明确:对不起。

假设我有一个理解:

代码语言:javascript
复制
for {v1<-Validation1(input)
     v2<-Validation2(v1)
     v3<-Validation3(v2)
} yield result

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

但是,如果Validation1、Validation2、Validation3的意见符合一些规则(例如:“这个人可以投票,因为他的年龄超过18岁,他的国籍是法国国籍”),他们就会成功。我想要的是跟踪应用的规则,以便能够在最后显示它们。

这显然是日志记录的用例。但我在路上犹豫不决:

:)

  • Other?

  1. 有一个对象" logger“,它可以被任何函数(Validation1、2和3,但也包括希望显示日志内容的调用者)访问。
  2. 使记录器成为Validation1、2和3
  3. 的参数,等待”Scala中的函数编程“的相关章节。

谢谢你的建议

编辑4月10日

因此,假设我想计算函数:x -> 1/sqrt(x)

首先,通过检查x>0来计算sqrt(x),如果不是零,则取逆。

对于scalaz.Validation,它很简单:

代码语言:javascript
复制
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建议的那样:

代码语言:javascript
复制
 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,这似乎很奇怪,而且按照我编写的方式,即使在失败的情况下,字符串的成功也会被记录下来:

代码语言:javascript
复制
 println(squareroot2(-1).run.run)

打印:(Squareroot,失败(不能取负数的squareroot ))

谢谢!贝诺特

编辑4月12日

所以Yo 8建议这个片段:

代码语言:javascript
复制
 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 (也就是标识)。

所以现在我们有:

代码语言:javascript
复制
   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”)是“丢失”的,所以不编译。

最后,我确实喜欢上了这个:

代码语言:javascript
复制
   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)

这意味着:

代码语言:javascript
复制
  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是善良的典范!)我向您提交完整的代码和错误:

代码语言:javascript
复制
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)
  }



}

这是终端的会话:

代码语言:javascript
复制
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日

编译您的代码时,我有第一个错误:

代码语言:javascript
复制
 could not find implicit value for parameter F:  scalaz.Pointed[Main.$anon.ValidationTExample.WriterAlias]

经过几次尝试,我以这样的方式重写了导入:

代码语言:javascript
复制
import scalaz.Writer
import scalaz.std.string._
import scalaz.Id._
import scalaz.WriterT
import scalaz.ValidationT
import scala.Math._

仍然有一个错误:

代码语言:javascript
复制
 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的最后一个版本:请注意,我必须构建它,而不是下载快照。

太好了!

对于那些感兴趣的人,以下是输出:

代码语言:javascript
复制
 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))

八号,如果有一天我们偶然见面,我会付你一瓶啤酒的!

贝诺特

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-03-28 13:18:16

为了在一元计算期间进行日志记录,您必须使用Writer实例。由于monad不构成并且您希望保持“验证”效果,所以您应该使用验证Monad转换器。我不知道您使用的是哪个版本的ScalaZ,但是Scalaz7 (分支服务器-7)提供了这样的单播转换器(即ValidationT)。

所以我们得到:

代码语言:javascript
复制
ValidationT[({type f[x] = Writer[W, x]})#f, A]

与你的记录器的类型

根据您的编辑,下面是我要做的

代码语言:javascript
复制
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)

现在,如何在理解中使用它

代码语言:javascript
复制
for {
  y <- squareroot(x).flatMapF(i => Writer("Squareroot ok", i))
  z <- inverse(y).flatMapF(i => Writer("Inverse ok", i))
} yield z

这些片段可能需要更多的类型注释。

编辑4月13日

下面是正确的方法类型注释:

代码语言:javascript
复制
 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]

这样,您就可以像这样定义结果方法:

代码语言:javascript
复制
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日

问题是:编译器无法解决

代码语言:javascript
复制
implicitly[Pointed[({ type f[x] = Writer[String, x] })#f]]

因为WriterT需要一个MonoidString和PointedId的实例。

代码语言:javascript
复制
import std.string._ // this import all string functions and instances
import Id._         // this import all Id functions and instances

以下是完整的可执行代码

代码语言:javascript
复制
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类型类库来减轻这些类型注释。

代码语言:javascript
复制
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)
}
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9896309

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档