Pattern match in foreach and then do a final step
Solution 1
I don't know what your ctm
is, but you could always do this:
val xs = List("date", "since", "other1", "other2")
xs.foreach { str =>
str match {
case "date" => println("Match Date")
case "since" => println("Match Since")
case unknow => println("Others")
}
println("Put your post step here")
}
Note you should use {}
instead of ()
when you want use a block of code as the argument of foreach().
Solution 2
I will not answer your question, but I should note that reassigning variables in Scala is a bad practice. I suggest you to rewrite your code to avoid var
s.
First, transform your strings to something else:
val strings = it map {
case "date" => "Current date: " + new Date().toString + "<br/>"
case "since" => "Last command executed: " + (ctm - last) + "ms before now<br/>"
case unknow => "Command: " + unknown + " not recognized <br/>"
}
Next, push it
strings map { out.push(_) }
It looks like your implementation of push
has side effects. Bad for you, because such methods makes your program unpredictable. You can easily avoid side effects by making push
return a tuple:
def push(s: String) = {
...
(ctm, last)
}
And using it like:
val (ctm, last) = out.push(str)
Update:
Of course side effects are needed to make programs useful. I only meant that methods depending on outer variables are less predictable than pure one, it is hard to reason about it. It is easier to test methods without side effects.
Yes, you should prefer val
s over var
s, it makes your program more "functional" and stateless. Stateless algorithms are thread safe and very predictable.
It seems like your program is stateful by nature. At least, try to stay as "functional" and stateless as you can :)
My suggested solution of your problem is:
// By convention, methods with side effects takes an empty argument list
def ctm(): Long = // Get current time
// Command handlers
def date() = "Current date: " + new Date().toString + "<br/>"
def since(last: Long) = "Last command executed: " + (ctm() - last) + "ms before now<br/>"
def unknown(cmd: String) = "Command: " + unknown + " not recognized <br/>"
// In your cmd processing loop
// First, map inputs to responses
val cmds = inps map {
case "date" => date()
case "since" => since(last)
case unk => unknown(unk)
}
// Then push responses and update state
cmds map { response =>
out.push(response)
// It is a good place to update your state
last = ctm()
}
It is hard to test this without context of your code, so you should fit it to your needs yourself. I hope I've answered your question.
Farmor
Updated on June 27, 2022Comments
-
Farmor almost 2 years
Is it possible to do anything after a pattern match in a
foreach
statement?
I want to do a post match step e.g. to set a variable. I also want to force a Unit return as myforeach
is String => Unit, and by default Scala wants to return the last statement.Here is some code:
Iteratee.foreach[String](_ match { case "date" => out.push("Current date: " + new Date().toString + "<br/>") case "since" => out.push("Last command executed: " + (ctm - last) + "ms before now<br/>") case unknow => out.push("Command: " + unknown + " not recognized <br/>") } // here I would like to set "last = ctm" (will be a Long) )
UPDATED: New code and context. Also new questions added :) They are embedded in the comments.
def socket = WebSocket.using[String] { request => // Comment from an answer bellow but what are the side effects? // By convention, methods with side effects takes an empty argument list def ctm(): Long = System.currentTimeMillis var last: Long = ctm // Command handlers // Comment from an answer bellow but what are the side effects? // By convention, methods with side effects takes an empty argument list def date() = "Current date: " + new Date().toString + "<br/>" def since(last: Long) = "Last command executed: " + (ctm - last) + "ms before now<br/>" def unknown(cmd: String) = "Command: " + cmd + " not recognized <br/>" val out = Enumerator.imperative[String] {} // How to transform into the mapping strategy given in lpaul7's nice answer. lazy val in = Iteratee.foreach[String](_ match { case "date" => out.push(date) case "since" => out.push(since(last)) case unknown => out.push(unknown) } // Here I want to update the variable last to "last = ctm" ).mapDone { _ => println("Disconnected") } (in, out) }