patternMinor
Attempting to eliminate var (and imperative style) from my Piece class
Viewed 0 times
varpiecestyleeliminateattemptingimperativeandfromclass
Problem
I've been cooking with gas since I got Daniel C Sobral's help on my last question. I am now re-reading Odersky's "Programming in Scala, 2nd Edition" (finished my first reading about this time last year).
I am eager to understand how to alter my mental modeling of problems to more fully embrace the functional programming style. However, I have spent hours looking at the code below attempting to figure out how to eliminate the var references. I am sure my imperative past is overshadowing and blinding me to functional possibilities.
I think I have retained overall "referential transparency" at each method; i.e. none of the var-ness escapes the local scope of the method (or function) within which it is defined. However, I would like to understand how I might achieve a higher level of functional programming purity, even if it is slightly unreasonable, within each method. I am more looking for ways I need to change my problem solving approaches to be more myopically functional in nature.
Specifically, how might I approach eliminate each instance of var.
Thank you for any guidance.
```
case class Bitmap2d(name: String, rowsByColumns: List[List[Boolean]], faceUp: Boolean) {
//require(rowsByColumns != null) //Assumed that if null was allowed as parameter, an Option would be used
require(validateRectangular, "all rows must have same length")
def validateRectangular: Boolean = {
rowsByColumns.forall(_.size / rowsByColumns.head.size == 1)
}
}
class Piece(name: String, charRep: Char, rowsByColumnsAndUp: List[List[Boolean]]) {
val translations = createTranslations()
def printTranslations() = {
println("Name: " + name + " Char: " + charRep)
for (bitmap2d = 0) && (bits 1) {
rowsByColumns.reverse
}
else {
rowsByColumns
}
}
private def translateAroundYAxis(rowsByColumns: List[List[Boolean]]) = {
if (rowsByColumns.head.size > 1) {
for (row <- rowsByColumns)
yield row.reverse
}
else {
rowsByCo
I am eager to understand how to alter my mental modeling of problems to more fully embrace the functional programming style. However, I have spent hours looking at the code below attempting to figure out how to eliminate the var references. I am sure my imperative past is overshadowing and blinding me to functional possibilities.
I think I have retained overall "referential transparency" at each method; i.e. none of the var-ness escapes the local scope of the method (or function) within which it is defined. However, I would like to understand how I might achieve a higher level of functional programming purity, even if it is slightly unreasonable, within each method. I am more looking for ways I need to change my problem solving approaches to be more myopically functional in nature.
Specifically, how might I approach eliminate each instance of var.
Thank you for any guidance.
```
case class Bitmap2d(name: String, rowsByColumns: List[List[Boolean]], faceUp: Boolean) {
//require(rowsByColumns != null) //Assumed that if null was allowed as parameter, an Option would be used
require(validateRectangular, "all rows must have same length")
def validateRectangular: Boolean = {
rowsByColumns.forall(_.size / rowsByColumns.head.size == 1)
}
}
class Piece(name: String, charRep: Char, rowsByColumnsAndUp: List[List[Boolean]]) {
val translations = createTranslations()
def printTranslations() = {
println("Name: " + name + " Char: " + charRep)
for (bitmap2d = 0) && (bits 1) {
rowsByColumns.reverse
}
else {
rowsByColumns
}
}
private def translateAroundYAxis(rowsByColumns: List[List[Boolean]]) = {
if (rowsByColumns.head.size > 1) {
for (row <- rowsByColumns)
yield row.reverse
}
else {
rowsByCo
Solution
One good technique at eliminating vars is recursion -- it can certainly be used in this example. Alternatively, you can identify a common pattern, such as fold, traversal, etc. For example:
Recursion:
Fold:
You can use the same techniques for the
In other places you might use
becomes:
Finally (unless I missed something), the
and so on.
var bitmaps = Set[List[List[Boolean]]]()
var result = List[Bitmap2d]()
for (
bitmap2dRaw <- bitmap2dRaws
if (!bitmaps.contains(bitmap2dRaw._2))
)
{
bitmaps += bitmap2dRaw._2;
result = Bitmap2d(bitmap2dRaw._1, bitmap2dRaw._2, bitmap2dRaw._3) :: result
}
result.reverseRecursion:
def getResult(bitmap2dRaws: ???, bitmap: Set[List[List[Boolean]]], result: List[Bitmap2d]): List[Bitmap2d] = bitmap2dRaws match {
case Seq(bitmap2dRaw, rest: _*) if (!bitmaps.contains(bitmap2dRaw._2) =>
getResult(rest, bitmaps + bitmap2dRaw._2, Bitmap2d(bitmap2dRaw._1, bitmap2dRaw._2, bitmap2dRaw._3) :: result)
case Seq(bitmap2dRaw, rest: _*) =>
getResult(rest, bitmaps, result)
case _ => result.reverse
}
getResult(bitmap2dRaws, Set[List[List[Boolean]], Nil)Fold:
bitmap2dRaws.foldLeft((Set[List[List[Boolean]]], List[Bitmap2d])) {
case ((bitmaps, result), bitmap2dRaw) if (!bitmaps.contains(bitmap2dRaw._2) =>
(bitmaps + bitmap2dRaw._2, Bitmap2d(bitmap2dRaw._1, bitmap2dRaw._2, bitmap2dRaw._3) :: result)
case ((bitmaps, result), _) => (bitmaps, result)
}._2.reverseYou can use the same techniques for the
var inside translateRotate90DegreesRight as well.In other places you might use
Option:private def translationDescription(bits: Int) = {
var result = List[String]()
if ((bits & 1) == 1) {
result = "FlipX" :: result
}
if ((bits & 2) == 2) {
result = "FlipY" :: result
}
if ((bits & 4) == 4) {
result = "Rotate" :: result
}
result.reverse
}becomes:
private def translationDescription(bits: Int) = {
val flipX = if ((bits & 1) == 1) Some("FlipX") else None
val flipY = if ((bits & 2) == 2) Some("FlipY") else None
val rotate = if ((bits & 4) == 4) Some("Rotate") else None
List(flipX, flipY, rotate).flatten // if this doesn't work, try flatMap(x => x)
}Finally (unless I missed something), the
var inside translateBasedOnBitsForXYR can be avoided simply by using multiple val, and if statements like this:val xTranslation = if ((bits & 1) == 1) translateAroundXAxis(rowsByColumns) else rowsByColumnsand so on.
Code Snippets
var bitmaps = Set[List[List[Boolean]]]()
var result = List[Bitmap2d]()
for (
bitmap2dRaw <- bitmap2dRaws
if (!bitmaps.contains(bitmap2dRaw._2))
)
{
bitmaps += bitmap2dRaw._2;
result = Bitmap2d(bitmap2dRaw._1, bitmap2dRaw._2, bitmap2dRaw._3) :: result
}
result.reversedef getResult(bitmap2dRaws: ???, bitmap: Set[List[List[Boolean]]], result: List[Bitmap2d]): List[Bitmap2d] = bitmap2dRaws match {
case Seq(bitmap2dRaw, rest: _*) if (!bitmaps.contains(bitmap2dRaw._2) =>
getResult(rest, bitmaps + bitmap2dRaw._2, Bitmap2d(bitmap2dRaw._1, bitmap2dRaw._2, bitmap2dRaw._3) :: result)
case Seq(bitmap2dRaw, rest: _*) =>
getResult(rest, bitmaps, result)
case _ => result.reverse
}
getResult(bitmap2dRaws, Set[List[List[Boolean]], Nil)bitmap2dRaws.foldLeft((Set[List[List[Boolean]]], List[Bitmap2d])) {
case ((bitmaps, result), bitmap2dRaw) if (!bitmaps.contains(bitmap2dRaw._2) =>
(bitmaps + bitmap2dRaw._2, Bitmap2d(bitmap2dRaw._1, bitmap2dRaw._2, bitmap2dRaw._3) :: result)
case ((bitmaps, result), _) => (bitmaps, result)
}._2.reverseprivate def translationDescription(bits: Int) = {
var result = List[String]()
if ((bits & 1) == 1) {
result = "FlipX" :: result
}
if ((bits & 2) == 2) {
result = "FlipY" :: result
}
if ((bits & 4) == 4) {
result = "Rotate" :: result
}
result.reverse
}private def translationDescription(bits: Int) = {
val flipX = if ((bits & 1) == 1) Some("FlipX") else None
val flipY = if ((bits & 2) == 2) Some("FlipY") else None
val rotate = if ((bits & 4) == 4) Some("Rotate") else None
List(flipX, flipY, rotate).flatten // if this doesn't work, try flatMap(x => x)
}Context
StackExchange Code Review Q#10696, answer score: 2
Revisions (0)
No revisions yet.