編輯:我更新了問題以便更具描述性。斯卡拉隱式轉換爲有效宏內的一元值
注:我使用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