5
\$\begingroup\$

I've just started teaching myself Scala to get my feet wet with functional programming, and I'm messing with around with some classical cryptography. The following code produces monoalphabetic simple substitution encryption, but I'm still trying to wrap my head around both Scala itself and functional style, so I'm sure this could be more concise and FP-oriented. For example, I'd love to get rid of var accumText and use a val instead, but I haven't been able to figure out how to make that work. Any advice on getting this more Scala-esque and FP-oriented would be greatly appreciated!

object SimpSub {
 // alphabet array
 private val alphabet = ('A' to 'Z').toList
 def main(args: Array[String]) {
 // split text into char list
 val text = args(0).toUpperCase.toList
 val key = args(1).toUpperCase.toList
 def buildCipherAlphabet(): List[Char] = {
 // build the cipher alphabet by concatenating the key to 
 // existing alphabet and removing duplicate letters
 return (key ::: alphabet).distinct
 }
 def encipher(): List[Char] = {
 // get the cipher alphabet
 val newAlph = buildCipherAlphabet()
 var accumText: String = "" 
 for (c <- text) {
 // add in whitespace
 if (c == ' ')
 accumText += c
 else
 // add the letter of the cipher alphabet corresponding to the current character
 // in the plaintext
 accumText += newAlph(alphabet.indexOf(c)) 
 }
 val cipherText = accumText.toList
 return cipherText
 }
 val cipherText = encipher()
 println("Plaintext: " + args(0))
 println("Key: " + args(1))
 print("Ciphertext: ")
 for (c <- cipherText)
 print(c)
 print("\n")
 }
}
asked Jul 8, 2015 at 18:16
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

encipher() deserves to be a full function with two parameters rather than just a closure within main(). It should take a key parameter first, because you can think of enciphering with a key as a transformation to be applied to the text. (For that matter, I suggest swapping your args(0) and args(1) as well.) The function would be more usable if it accepts and returns strings instead of lists.

Instead of writing args(0) twice and args(1) twice, you should assign text and key more appropriately, by not munging them prematurely with .toUpperCase.toList. I also suggest using destructuring to assign both values at once.

With the changes above, main() can look very clean.

As for the encipher() function, you can simplify it by using

  • for-comprehensions instead of repeated concatenation to an empty string
  • pattern matching instead of if-else.
object SimpSub {
 private val alphabet = ('A' to 'Z').toList
 def encipher(key: String, text: String): String = {
 // Build the cipher alphabet by concatenating the key to
 // the alphabet and removing duplicate letters
 val cipherAlphabet = (key.toUpperCase.toList ::: alphabet).distinct
 val cipherText = for (c <- text.toUpperCase) yield c match {
 case ' ' => ' '
 case _ => cipherAlphabet(alphabet.indexOf(c))
 }
 return cipherText.mkString
 }
 def main(args: Array[String]) {
 val Array(text, key) = args
 println("Plaintext: " + text)
 println("Key: " + key)
 println("Ciphertext: " + encipher(key, text))
 }
}
answered Jul 8, 2015 at 19:11
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Wow, that really cleaned up a lot. I definitely need to get in the mindset of using for-comprehensions more. Thanks! \$\endgroup\$ Commented Jul 8, 2015 at 20:14

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.