• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

斯卡拉隐式转换为有效宏内的一元值

原作者: [db:作者] 来自: 网络 收藏 邀请

编辑:我更新了问题以便更具描述性。斯卡拉隐式转换为有效宏内的一元值

注:我使用Scala 2.11编译器,因为这是LMS教程项目使用的编译器版本。

我正在将用Haskell编写的DSL移植到Scala。 DSL是一种命令式语言,所以我使用了单引号,即WriterT [Stmt] (State Label) a。我无法将其移植到Scala,但是通过使用ReaderWriterState monad和仅使用Unit来获得Reader组件,解决了这个问题。然后,我开始寻找Haskell中的符号替代方法。理解被认为是Scala中的这种替代方法,但它们是针对序列量身定制的,例如,无法匹配一个元组,它会插入一个调用filter。所以我开始寻找替代品并找到了多个库:effectful,monadlesseach。我首先尝试了effectful,这正是我想要达到的目标,我甚至更喜欢Haskell的do-notation,并且它与我一直使用的ScalaZReaderWriterState monad运行良好。在我的DSL中,我有类似Drop()(案例类)的操作,我希望能够直接作为语句使用。我希望用implicits这一点,但由于effectful!方法(或monadless等同为此事)太一般了,我不能让斯卡拉我Action case类自动转换为Stmt类型(即返回UnitReaderWriterState)的东西。

所以,如果没有牵连,会有不同的方式来实现它?

Main.passes2所示,我弄清楚了一个我不介意使用的解决方法,但我很好奇我是偶然遇到语言的一些限制,还是仅仅是我缺乏Scala的经验。

随着Main.fails1我会收到以下错误信息:隐未找到:scalaz.Unapply[scalaz.Monad, question.Label]。无法将类型question.Label无法应用到按类型scalaz.Monad分类的类型M[_]的类型构造函数中。检查是否通过编译implicitly[scalaz.Monad[type constructor]]来定义类型类别,并检查对象Unapply中的含义,该对象仅涵盖常见类型的“形状”。

它来自ScalaZ其Unapplyhttps://github.com/scalaz/scalaz/blob/d2aba553e444f951adc847582226d617abae24da/core/src/main/scala/scalaz/Unapply.scala#L50

而且随着Main.fails2我只会得到:值!不是question.Label

成员,我认为它是只写失踪隐含定义的问题,但我不确定Scala希望我写的是哪一个。

我的构建中最重要的部分。SBT是版本:

scalaVersion := "2.11.2", 

而且依赖:

libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.11.2", 
libraryDependencies += "org.scala-lang" % "scala-library" % "2.11.2", 
libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.11.2", 
libraryDependencies += "org.pelotom" %% "effectful" % "1.0.1", 

下面是相关的代码,包含我试过必要的东西和代码运行的那些事:

package question 

import scalaz._ 
import Scalaz._ 

import effectful._ 

object DSL { 
    type GotoLabel = Int 
    type Expr[A] = ReaderWriterState[Unit, List[Action], GotoLabel, A] 
    type Stmt = Expr[Unit] 

    def runStmt(stmt: Stmt, startLabel: GotoLabel): (Action, GotoLabel) = { 
    val (actions, _, updatedLabel) = stmt.run(Unit, startLabel) 
    val action = actions match { 
     case List(action) => action 
     case _ => Seq(actions) 
    } 
    (action, updatedLabel) 
    } 

    def runStmt(stmt: Stmt): Action = runStmt(stmt, 0)._1 

    def getLabel(): Expr[GotoLabel] = 
    ReaderWriterState((_, label) => (Nil, label, label)) 

    def setLabel(label: GotoLabel): Stmt = 
    ReaderWriterState((_, _) => (Nil, Unit, label)) 

    implicit def actionStmt(action: Action): Stmt = 
    ReaderWriterState((_, label) => (List(action), Unit, label)) 
} 

import DSL._ 

final case class Label(label: String) extends Action 
final case class Goto(label: String) extends Action 
final case class Seq(seq: List[Action]) extends Action 
sealed trait Action { 
    def stmt(): Stmt = this 
} 

object Main { 
    def freshLabel(): Expr[String] = effectfully { 
    val label = getLabel.! + 1 
    setLabel(label).! 
    s"ants-$label" 
    } 

    def passes0() = 
    freshLabel() 
     .flatMap(before => Label(before)) 
     .flatMap(_ => freshLabel()) 
     .flatMap(after => Label(after)); 

    def passes1() = effectfully { 
    unwrap(actionStmt(Label(unwrap(freshLabel())))) 
    unwrap(actionStmt(Label(unwrap(freshLabel())))) 
    } 

    def fails1() = effectfully { 
    unwrap(Label(unwrap(freshLabel()))) 
    unwrap(Label(unwrap(freshLabel()))) 
    } 

    def pasess2() = effectfully { 
    Label(freshLabel.!).stmt.! 
    Label(freshLabel.!).stmt.! 
    } 

    def fails2() = effectfully { 
    Label(freshLabel.!).! 
    Label(freshLabel.!).! 
    } 

    def main(args: Array[String]): Unit = { 
    runStmt(passes0()) 
    } 
} 

回答

1

问题质量

我想先抱怨质量问题。你几乎不提供你想要实现的内容的文本描述,然后向我们展示一段代码,但不明确引用你的依赖关系。这远远不能算作Minimal, Complete, and Verifiable example。通常,如果您提供易于理解和重现的明确问题,您将有更多机会获得一些答案。

回到业务

当你喜欢写东西

unwrap(Label(unwrap(freshLabel()))) 

您从Scala编译器要求太多。特别是unwrap只能解包一些Monad,但Label不是一个monad。这不仅仅是因为没有Monad[Label]实例,事实上它在结构上不适合杀死你。简单来说,ScalaZ Unapply的一个实例是一个对象,允许您将应用的泛型类型MonadType[SpecificType](或其他FunctorType[SpecificType])拆分为“未应用”/“部分应用”MonadType[_]SpecificType,即使(在您的情况下)MonadType[_]实际上像ReaderWriterState[Unit, List[Action], GotoLabel, _]这样复杂的东西。所以错误表示没有已知的方法将Label分成MonadType[_]SpecifictType。你可能希望你的implicitactionStmt会做的伎俩来自动转换LabelStatement但是这一步是太多Scala编译器,因为它的工作,这也意味着分裂复合型。请注意,由于unwrap本身就是一种可处理任何Monad的通用方法,因此编译器的转换远不是明显的。实际上ScalaZ在某种意义上需要Unapply,因为编译器不能自动执行这些操作。不过,如果你帮助编译器只是一点点通过指定泛型类型,它可以做的工作休息:

def fails1() = effectfully { 
    // fails 
    // unwrap(Label(unwrap(freshLabel()))) 
    // unwrap(Label(unwrap(freshLabel()))) 

    // works 
    unwrap[Stmt](Label(unwrap(freshLabel()))) 
    unwrap[Stmt](Label(unwrap(freshLabel()))) 
} 

也有另一种可能的解决方案,但它是一个非常肮脏的黑客:你可以滚了你定制Unapply说服编译器Label实际上是一样的Expr[Unit]可以被分割为Expr[_]Unit

implicit def unapplyAction[AC <: Action](implicit TC0: Monad[Expr]): Unapply[Monad, AC] { 
    type M[X] = Expr[X] 
    type A = Unit 
    } = new Unapply[Monad, AC] { 
    override type M[X] = Expr[X] 
    override type A = Unit 

    override def TC: Monad[Expr] = TC0 

    // This can't be implemented because Leibniz really witness only exactly the same types rather than some kind of isomorphism 
    // Luckily effectful doesn't use leibniz implementation   
    override def leibniz: AC === Expr[Unit] = ??? 
    } 

最明显的原因,这是一个肮脏的黑客是Label实际上是不一样的Expr[Unit],你可以看到它,因为你不能在你的Unapply中实现leibniz。无论如何,如果您导入unapplyAction,即使您的原始fails1也会编译并工作,因为有效的内部不会使用leibniz

至于你的fails2,我认为你不能以任何简单的方式工作。可能您尝试的唯一方法是创建另一个宏,将您的action(或其隐式包装器)上的!就地调用转换为action.stmt上的effectful!。这可能工作,但我没有尝试。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
如何在应用程序启动期间获取位置发布时间:2022-02-24
下一篇:
的Symfony2在督促发布时间:2022-02-24
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap