编辑:我更新了问题以便更具描述性。斯卡拉隐式转换为有效宏内的一元值
注:我使用Scala 2.11编译器,因为这是LMS教程项目使用的编译器版本。
我正在将用Haskell编写的DSL移植到Scala。 DSL是一种命令式语言,所以我使用了单引号,即WriterT [Stmt] (State Label) a
。我无法将其移植到Scala,但是通过使用ReaderWriterState
monad和仅使用Unit来获得Reader
组件,解决了这个问题。然后,我开始寻找Haskell中的符号替代方法。理解被认为是Scala中的这种替代方法,但它们是针对序列量身定制的,例如,无法匹配一个元组,它会插入一个调用filter
。所以我开始寻找替代品并找到了多个库:effectful
,monadless
和each
。我首先尝试了effectful
,这正是我想要达到的目标,我甚至更喜欢Haskell的do-notation,并且它与我一直使用的ScalaZ
的ReaderWriterState
monad运行良好。在我的DSL中,我有类似Drop()
(案例类)的操作,我希望能够直接作为语句使用。我希望用implicits这一点,但由于effectful
的!
方法(或monadless
等同为此事)太一般了,我不能让斯卡拉我Action
case类自动转换为Stmt
类型(即返回Unit
的ReaderWriterState
)的东西。
所以,如果没有牵连,会有不同的方式来实现它?
如Main.passes2
所示,我弄清楚了一个我不介意使用的解决方法,但我很好奇我是偶然遇到语言的一些限制,还是仅仅是我缺乏Scala的经验。
随着Main.fails1
我会收到以下错误信息:隐未找到:scalaz.Unapply[scalaz.Monad, question.Label]
。无法将类型question.Label
无法应用到按类型scalaz.Monad
分类的类型M[_]
的类型构造函数中。检查是否通过编译implicitly[scalaz.Monad[type constructor]]
来定义类型类别,并检查对象Unapply
中的含义,该对象仅涵盖常见类型的“形状”。
它来自ScalaZ其Unapply
:https://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())
}
}
我觉得你对问题质量的第一个评论很不公平,考虑到我努力去做你所抱怨的事情。限制代码大小,但仍提供足够的空间来提供一些上下文。关于文本描述,我问了这个问题,我提到了一个特定的代码片段,在文本中也没有提及这一点。诚然,我展示了我试图做的不是文本上的,而是通过代码,但我希望更清楚。我怀疑我是否应该提供build.sbt,但希望我的进口清楚。 –
那边,谢谢你彻底的回答!特别是不适用的定义有助于理解我应该如何去做。考虑到我的目标是减少语法噪音,我可能会尝试你的第三种方法,看看我是否可以制作自己的调用其他宏的宏。 –
@OttidMes,关于这个问题的部分可能不公平,但我分享了我在尝试回答时的经验。而且我认为在我之前缺乏其他答案是一个迹象,表明你的问题远非完美。我仍然坚信,对你的意图的文本描述是任何非平凡问题的必须要求,因为我相信“[阅读代码比编写代码更难。](https://www.joelonsoftware .COM/2000/04/06 /东西 - 你 - 应该 - 永远-DO部分-I /)_”。 – SergGr