如何以惯用的Scala/FP方式存储请求队列

如何以惯用的Scala/FP方式存储请求队列,scala,functional-programming,Scala,Functional Programming,正如标题所说,我试图将一些命令存储在我正在编写的程序(代码生成器)中,只是为了在稍后阶段解释它们 这主要是因为一些命令需要其他人提供信息,我认为我最好不要对命令发送者强制执行非常严格的命令(尽管这种选择也有一个缺点,即很难决定命令是否有效) 问题很简单:在Scala中,除了缓冲区之外,我想不出任何其他集合来表示这个命令队列。在我的例子中不需要并发性,使用一次更新一个元素的不可变集合感觉很愚蠢 另一方面,我希望在我的程序中尽可能地减少可变性——这是一个可以合理实现的地方吗?还是我的直觉正确,缓冲区

正如标题所说,我试图将一些命令存储在我正在编写的程序(代码生成器)中,只是为了在稍后阶段解释它们

这主要是因为一些命令需要其他人提供信息,我认为我最好不要对命令发送者强制执行非常严格的命令(尽管这种选择也有一个缺点,即很难决定命令是否有效)

问题很简单:在Scala中,除了缓冲区之外,我想不出任何其他集合来表示这个命令队列。在我的例子中不需要并发性,使用一次更新一个元素的不可变集合感觉很愚蠢

另一方面,我希望在我的程序中尽可能地减少可变性——这是一个可以合理实现的地方吗?还是我的直觉正确,缓冲区自然适合我的情况

这是一个草图,展示了如果使用不可变集合,该存储将是什么样子。(一个终止命令会说我们已经完成了对给定符号的更新,然后可以通过解释其唯一的BuildCommand和零个或多个updateCommand来构造该符号)


任何
Seq
看起来都很合适


在转换为不可变的
Seq

之前,您可以从可变的
缓冲区开始追加命令。如果您只追加操作,然后按顺序访问它们,我想不出比不可变列表更合适的方法了。只需使用
Seq()

我必须指出,大多数不可变集合在追加时不会复制整个内容,它们共享大量数据(它们可以,因为一切都是不可变的)。在注销之前做一些分析。我喜欢矢量。@experquisite效率不是我在这里最关心的。我主要是说“如果感觉很傻”,因为一个不可变的集合会涉及到一个丑陋的变量。而且会创建很多中间集合(不管是不是lightwheight),这让我觉得有些浪费。如果你在执行命令式循环,它只会涉及一个变量?听起来你可以把一个不可变的Seq展开?@experquisite好吧,我已经编辑了这篇文章并添加了一些代码(如果没有它,我的问题太枯燥了,那就很抱歉了)。你能在这里避免var吗?命令一次出现一个(例如,“将数组x值设置为5”)为什么不能让
解释(Seq[changecondrom],Command)=>(Seq[changecondrom],Option[output])
那么这里就不会有任何状态,而且作为一种奖励,单元测试非常容易。这并不是说它会使你的观点无效,但这些命令将不会依次访问。相反,相关命令将通过应用
filter
find
操作进行集群,然后一起解释。我想我会选择可变的进行积累,不可变的进行处理,我在最初的帖子中的评论证明了这一点。我认为您的答案是完全有效的,认为将中间的东西存储到<代码>缓冲区直到它“成熟”,然后被处理成不可变的<代码> SEQ 似乎是最直接的方法。虽然我同意我的解释器如果是无状态的会更好,但这就是我现在要使用的。
trait Outcome
sealed trait Command {
  def symId : String
}
sealed trait ChangeCommand extends Command
sealed trait BuildCommand extends Command
sealed trait UpdateCommand extends Command
final case class TerminationCommand(symId: String) extends Command

var comQueue = immutable.Seq[ChangeCommand]()

private def translate(sId : String) : Outcome = {
  val forSymb = comQueue filter {_.symId}
  //...
}

def interpret(c : Command) = c match {
  case cc : ChangeCommand    => 
    comQueue = comQueue + cc
    None
  case TerminationCommand(s) =>
    Some(translate(s))
}