Scala REPL中的嵌套环境

Scala REPL中的嵌套环境,scala,scala-repl,Scala,Scala Repl,是否可以在Scala REPL中创建(输入)嵌套环境,以便在退出嵌套环境后,在退出的环境中创建的所有变量绑定都将丢失 以下是我希望会议的样子: scala> val x = 1 x: Int = 1 scala> enter // How to implement this? // Entering nested context (type exit to exit) scala> val x = 2 x: Int = 2 scala> val y = 3 y: I

是否可以在Scala REPL中创建(输入)嵌套环境,以便在退出嵌套环境后,在退出的环境中创建的所有变量绑定都将丢失

以下是我希望会议的样子:

scala> val x = 1
x: Int = 1

scala> enter // How to implement this?
// Entering nested context (type exit to exit)

scala> val x = 2
x: Int = 2

scala> val y = 3
y: Int = 3

scala> exit // How to implement this?
// Exiting nested context

scala> assert(x == 1)

scala> y
<console>:12: error: not found: value y
       y
       ^

scala> 
scala>val x=1
x:Int=1
scala>enter//如何实现这一点?
//输入嵌套上下文(键入exit以退出)
scala>val x=2
x:Int=2
scala>valy=3
y:Int=3
scala>exit//如何实现这一点?
//退出嵌套上下文
scala>assert(x==1)
scala>y
:12:错误:未找到:值y
Y
^
斯卡拉>

对于当前的Scala REPL,这是不可能的,但您可以使用以下方法实现类似的功能:

这些会话并不完全按照您描述的方式嵌套,但很容易按名称跟踪,并且可以重叠。也就是说,在
repl.sess.save(“first”)
之后,如果不覆盖原始
x
,您仍然可以访问它


在对它进行了更多的研究之后,我能够创建一个简单的对象,它使用堆栈跟踪会话并加载/保存会话。可以将其放置在
~/.ammonite/predef.sc
中,以使用ammonite REPL自动加载:

object SessionStack {

    case class AmmSession(id: Int = 1) {
        def name = s"session_${id}"
        def next = AmmSession(id + 1)
    }

    private var sessions = collection.mutable.Stack.empty[AmmSession]

    private var current = AmmSession()

    def enter: Unit = {
        sessions.push(current.copy())
        repl.sess.save(current.name)
        current = current.next
    }

    def exit: Unit = if(sessions.nonEmpty) {
        current = sessions.pop()
        repl.sess.load(current.name)
    } else {
        println("Nothing to exit.")
    }

}
import SessionStack._

我还没有对此进行严格的测试,因此可能有一个边缘案例没有覆盖,但我能够轻松地深入几层,然后剥下这些层。

那太棒了。我认为没有一个repl可以做到这一点,但是的,请!我没有可用的REPL,但当您用
{
输入一个块并用
}
保留它时,它可能会工作。所有变量都应该只存在于这个块中,就像
{/*做你的事*/};y/@ThomasPawlitzki如果这是真的,则在关闭之前不会对整个块进行求值。我需要在嵌套环境中保持交互性。请访问谢谢,这很有趣。虽然我确实希望嵌套作用域,即外部作用域的绑定在内部作用域中可用。@TomasMikula在调用
repl.sess.save(“first”)
后,您仍然可以访问
x
,因此您仍然可以实现类似的效果,只是不那么方便。它本质上允许您在重新加载时“回滚”到保存点。哦,在这种情况下,我可以使用全局变量(会话名称堆栈)实现
enter
exit
?@TomasMikula查看我的编辑。我想这会满足你使用Ammonite REPL的需求。
object SessionStack {

    case class AmmSession(id: Int = 1) {
        def name = s"session_${id}"
        def next = AmmSession(id + 1)
    }

    private var sessions = collection.mutable.Stack.empty[AmmSession]

    private var current = AmmSession()

    def enter: Unit = {
        sessions.push(current.copy())
        repl.sess.save(current.name)
        current = current.next
    }

    def exit: Unit = if(sessions.nonEmpty) {
        current = sessions.pop()
        repl.sess.load(current.name)
    } else {
        println("Nothing to exit.")
    }

}
import SessionStack._