加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

在Scala中为嵌套类编写类型类实例

发布时间:2020-12-16 09:25:52 所属栏目:安全 来源:网络整理
导读:在 this recent Stack Overflow question中,作者想要将某种类型的解析器列表更改为返回该类型列表的解析器.我们可以想象使用Scalaz的应用仿函数序列来做到这一点: import scala.util.parsing.combinator._import scalaz._import Scalaz._object parser exte
在 this recent Stack Overflow question中,作者想要将某种类型的解析器列表更改为返回该类型列表的解析器.我们可以想象使用Scalaz的应用仿函数序列来做到这一点:

import scala.util.parsing.combinator._

import scalaz._
import Scalaz._

object parser extends RegexParsers {
  val parsers = List(1,2,3).map(repN(_,"""d+""".r))
  def apply(s: String) = parseAll(parsers.sequence,s)
}

这里我们列出三个返回整数列表的解析器,并将其转换为一个返回整数列表列表的解析器.不幸的是,Scalaz没有为Parser提供Applicative实例,所以这段代码不能编译,但这很容易解决:

import scala.util.parsing.combinator._

import scalaz._
import Scalaz._

object parser extends RegexParsers {
  val parsers = List(1,s)

  implicit def ParserPure: Pure[Parser] = new Pure[Parser] {
    def pure[A](a: => A) = success(a)
  }

  implicit def ParserFunctor: Functor[Parser] = new Functor[Parser] {
    def fmap[A,B](p: Parser[A],f: A => B) = p.map(f)
  }

  implicit def ParserBind: Bind[Parser] = new Bind[Parser] {
    def bind[A,f: A => Parser[B]) = p.flatMap(f)
  }
}

这按预期工作:例如,解析器(“1 2 3 4 5 6”)给出了List(List(1),List(2,3),List(4,5,6)).

(我知道我可以给一个Apply实例,但Bind实例更简洁.)

每次我们扩展Parsers时都不必这样做,但我不清楚如何更普遍地获得Parsers#Parser的Applicative实例.以下天真的方法当然不起作用,因为我们需要Parsers的实例是相同的:

implicit def ParserBind: Bind[Parsers#Parser] = new Bind[Parsers#Parser] {
  def bind[A,B](p: Parsers#Parser[A],f: A => Parsers#Parser[B]) = p.flatMap(f)
}

我很清楚这应该是可行的,但是我对Scala的类型系统不太满意,知道如何去做.有什么简单的东西让我失踪吗?

回答下面的答案:我确实尝试了-Ydependent-method-types路由,并且做到了这一点:

implicit def ParserApplicative(g: Parsers): Applicative[g.Parser] = {
  val f = new Functor[g.Parser] {
    def fmap[A,B](parser: g.Parser[A],f: A => B) = parser.map(f)
  }

  val b = new Bind[g.Parser] {
    def bind[A,B](p: g.Parser[A],f: A => g.Parser[B]) = p.flatMap(f)
  }

  val p = new Pure[g.Parser] {
    def pure[A](a: => A) = g.success(a)
  }

  Applicative.applicative[g.Parser](p,FunctorBindApply[g.Parser](f,b))
}

问题(正如didierd所指出的)是,目前还不清楚如何让隐含的内容进入.所以这种方法确实有效,但你必须在你的语法中添加如下内容:

implicit val applicative = ParserApplicative(this)

那时mixin方法显然更具吸引力.

(作为旁注:我希望能够在上面简单地编写Applicative.applicative [g.Parser],但这会产生错误,说编译器无法找到Pure [g.Parser]的隐含值 – 尽管如此一个人坐在它旁边.显然,对于依赖方法类型的工作方式存在一些不同.)

感谢retronym指出了一个完成我想要的技巧.我从his code抽象了以下内容:

implicit def parserMonad[G <: Parsers with Singleton] =
  new Monad[({ type L[T] = G#Parser[T] })#L] {
    def pure[A](a: => A): G#Parser[A] = {
      object dummy extends Parsers
      dummy.success(a).asInstanceOf[G#Parser[A]]
    }

    def bind[A,B](p: G#Parser[A],f: (A) => G#Parser[B]): G#Parser[B] =
      p.flatMap(f)
  }

如果你在范围内有这个,你可以在扩展Parsers的任何对象中获得Parser的monad实例.这是一种作弊,因为演员,但仍然很整洁.

解决方法

我通常在mixins for Parsers中为Parser添加隐式扩展

trait BindForParser extends Parsers {
  implicit def ParserBind = new Bind[Parser] {
    def bind[A,f: A => Parser[B]) = p flatMap f
  }
}

然后你只需要在你的语法(Parsers)中混合使用,并且由于Parser实例通常只在Parsers中操作,之后没有太多机会需要mixin,当语法完成并且你不能再混合使用在你的例子中,你就是这么做的

object parser extends Parsers with BindForParser

在更一般的问题上,是否有可能“从外部”这样做,最直接的方式可能就是这样

implicit def ParserBind(grammar: Parsers) = new Bind[grammar.Parser] {
  def bind[A,B](p: grammar.Parser[A],f: A => grammar.Parser[B]) = p flatMap f
}

但是这是不允许的,方法参数(此处为语法)不被视为稳定标识符,因此不允许将grammar.Parser作为类型.但是可以选择-Xexperimental.但即便如此,我还是看不到隐含会在需要时如何发挥作用.我们想要的是一个隐式的Bind [grammar.Parser],并且使用语法参数,这不是我们所拥有的.

所以我的回答是无法做到的,但如果有人想出点什么我就不会感到惊讶.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读