patternMinor
Converting imperative style user input menu to functional programming style
Viewed 0 times
userprogramminginputstylemenuimperativefunctionalconverting
Problem
I am currently trying to teach myself scala by rewriting projects from my intro CS class, which was taught in C++. In addition to just learning the syntax I am trying to gain understanding of how functional programming works and what is considered good functional programming style.
Below I've included both the original code, which is a simple while loop that continues looping until the user selects the 'quit' option, and my attempt at a functional equivalent. Have I done this correctly? What could be improved?
Original imperative version in C++:
My attempt at a functional version in scala:
Below I've included both the original code, which is a simple while loop that continues looping until the user selects the 'quit' option, and my attempt at a functional equivalent. Have I done this correctly? What could be improved?
Original imperative version in C++:
int main()
{
int option = -1;
while (option != 3)
{
cout > option;
if (option == 1)
{
cout << "selected 1" << endl;
}
else if (option == 2)
{
cout << "selected 2" << endl;
}
else if (option == 3)
{
cout << "selected quit.\n";
}
else
{
cout << "Sorry, that command is not recognized. ";
}
}
return 0;
}My attempt at a functional version in scala:
def menu(option: Int) {
println("""|Please select one of the following:
| 1 - one
| 2 - two
| 3 - quit""".stripMargin)
if (option == 1) {
println("selected 1")
val opt = StdIn.readInt
menu(opt)
}
else if (option == 2) {
println("selected 2")
val opt = StdIn.readInt
menu(opt)
}
else if (option == 3) {
println("selected quit")
}
else {
println("Sorry, that command is not recognized")
}
}
def main(args: Array[String]) {
println("""|Please select one of the following:
| 1 - one
| 2 - two
| 3 - quit""".stripMargin)
val opt = StdIn.readInt
menu(opt)
}Solution
One of the Scala features you need to get used to using is
Also, the way you have defined
Finally, you have repeated the printing of the menu and reading of the option. In general, one should follow Don't Repeat Yourself.
So how about something like the code below. Note, one of the rare cases tailor made for
Alternately, if you wanted to something more functional, you could change
Where
match - it is your friend. One of your very best friends.Also, the way you have defined
menu is recursive, with no bounding. In this particular case, it's probably not an issue, but it is, in general a Really Bad Idea.Finally, you have repeated the printing of the menu and reading of the option. In general, one should follow Don't Repeat Yourself.
So how about something like the code below. Note, one of the rare cases tailor made for
do...while.def menu(option: Int): Boolean = {
option match {
case 1 =>
println("selected 1")
true
case 2 =>
println("selected 2")
true
case 3 =>
println("selected quit")
false
case _ => // the else case
println("Sorry, that command is not recognized")
true
}
}
def readOption: Int = {
println("""|Please select one of the following:
| 1 - one
| 2 - two
| 3 - quit""".stripMargin)
StdIn.readInt()
}
def main(args: Array[String]) {
var opt = 0
do {
opt = readOption
} while (menu(opt))
}Alternately, if you wanted to something more functional, you could change
menu to something like this:val actionMap = Map[Int, () => Boolean](1 -> handleOne, 2 -> handleTwo, 3 ->handleThree)
def handleOne(): Boolean = {
println("selected 1")
true
}
def handleTwo(): Boolean = {
println("selected 2")
true
}
def handleThree(): Boolean = {
println("selected quit")
false
}
def menu(option: Int): Boolean = {
actionMap.get(option) match {
case Some(f) => f()
case None =>
println("Sorry, that command is not recognized")
false
}
}Where
actionMap maps each Int to a function that takes no parameters and returns a Boolean. In menu, we use option as the key into the map and then call the result (if there is one).Code Snippets
def menu(option: Int): Boolean = {
option match {
case 1 =>
println("selected 1")
true
case 2 =>
println("selected 2")
true
case 3 =>
println("selected quit")
false
case _ => // the else case
println("Sorry, that command is not recognized")
true
}
}
def readOption: Int = {
println("""|Please select one of the following:
| 1 - one
| 2 - two
| 3 - quit""".stripMargin)
StdIn.readInt()
}
def main(args: Array[String]) {
var opt = 0
do {
opt = readOption
} while (menu(opt))
}val actionMap = Map[Int, () => Boolean](1 -> handleOne, 2 -> handleTwo, 3 ->handleThree)
def handleOne(): Boolean = {
println("selected 1")
true
}
def handleTwo(): Boolean = {
println("selected 2")
true
}
def handleThree(): Boolean = {
println("selected quit")
false
}
def menu(option: Int): Boolean = {
actionMap.get(option) match {
case Some(f) => f()
case None =>
println("Sorry, that command is not recognized")
false
}
}Context
StackExchange Code Review Q#84989, answer score: 7
Revisions (0)
No revisions yet.