修改:我将问题更新为更具描述性。
注意:我使用的是Scala 2.11编译器,因为这是LMS教程项目使用的编译器版本。
我正在将用Haskell编写的DSL移植到Scala。 DSL是一种命令式语言,因此我使用带有标记的monad,即WriterT [Stmt] (State Label) a
。我将此移植到Scala时遇到了麻烦,但是使用ReaderWriterState
monad并使用Unit作为Reader
组件来解决这个问题。然后我开始寻找Haskell中发现的do-notation的替代方案。在Scala中,For-comprehension应该是这种替代方案,但它们是针对序列而定制的,例如,无法模式匹配元组,它会插入对filter
的调用。所以我开始寻找替代方案并找到了多个库:effectful
,monadless
和each
。我首先尝试了effectful
,这完全符合我想要实现的目标,我甚至更喜欢Haskell的符号,并且它与我曾经使用过的ReaderWriterState
ScalaZ
monad一起工作得很好。在我的DSL中,我有Drop()
(案例类)之类的操作,我希望它能够直接用作语句。我希望对此使用含义,但因为!
effectful
方法(或monadless
相当于此问题)的Action
方法过于笼统,我无法让Scala自动转换{{1案例类为Stmt
类型的东西(返回ReaderWriterState
的{{1}})。
因此,如果不是暗示,是否会有不同的方法来实现它?
如Unit
所示,我确实找到了一个我不介意使用的解决方法,但我很好奇我是偶然发现了语言的某些限制,还是仅仅是我缺乏Scala的经验。
使用Main.passes2
我将收到以下错误消息:未找到隐式:Main.fails1
。无法取消将scalaz.Unapply[scalaz.Monad, question.Label]
类型应用于按类型question.Label
分类的类型M[_]
的atype构造函数。检查类型类是通过编译scalaz.Monad
来定义的,并查看对象implicitly[scalaz.Monad[type constructor]]
中的含义,它只涵盖常见的“形状”。
来自ScalaZ的Unapply
:https://github.com/scalaz/scalaz/blob/d2aba553e444f951adc847582226d617abae24da/core/src/main/scala/scalaz/Unapply.scala#L50
使用Unapply
我会得到:值Main.fails2
不是!
的成员
我认为这只是编写缺少的隐式定义的问题,但我不太确定Scala希望我写哪一个。
我的build.sbt最重要的部分是版本:
question.Label
依赖项:
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",
答案 0 :(得分:1)
质量问题
我想首先抱怨质量问题。您几乎没有提供您要实现的内容的文本描述,然后向我们展示一段代码,但不要明确引用您的依赖项。这远远不能算作Minimal, Complete, and Verifiable example。如果您提供易于理解和重现的明确问题,通常您会有更多机会获得答案。
返回商家
当你写
之类的东西时unwrap(Label(unwrap(freshLabel())))
你从Scala编译器那里问得太多了。特别是unwrap
只能解包包含在某些Monad
中的内容,但Label
不是monad。事实上,没有Monad[Label]
实例,事实上它在结构上并不适合杀死你。简单地说,ScalaZ Unapply
的一个实例是一个对象,允许您将应用的泛型类型MonadType[SpecificType]
(或其他FunctorType[SpecificType]
)拆分为"未应用" /&# 34;部分应用" MonadType[_]
和SpecificType
即使(在您的情况下)MonadType[_]
实际上像ReaderWriterState[Unit, List[Action], GotoLabel, _]
那样复杂。因此,错误表明没有已知方法可以将Label
拆分为某些MonadType[_]
和SpecifictType
。您可能希望implicit
actionStmt
能够将Label
自动转换为Statement
,但这一步对于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]
不同,你可以通过你无法实现{{1}这一事实来看待它在你的leibniz
中。无论如何,如果您导入Unapply
,即使您的原始unapplyAction
也会编译并正常工作,因为有效的内部不会使用fails1
。
至于您的leibniz
,我认为您无法以任何简单的方式使其发挥作用。可能您尝试的唯一方法是创建另一个宏,将您的fails2
(或其隐式包装器)上的就地呼叫转换为!
到action
&#39; effectful
上的!
。这可能有用,但我没有尝试过。