# How to write this function without all the type declarations

Is there a way to write this function without all the type declarations?

code on scastie

I wanted to write the transform functions like this, but couldn’t make it work.

``````    def r90(x,y) = (/(y), x)
def r180(x,y) = (/(x), /(y))
...
``````

and then

``````    val transforms = List[(Byte,Byte) => POSITION](id, r90,  r180, r270,
my, mx, mxy, mxr90)
transforms.map { tr =>
placement.map { p: POSITION => tr.tupled(p) }
}
``````

Do you care about the names of the functions?

If not, I would do this:

``````val transforms: List[POSITION => POSITION] = List(
x => x // id = x, y
{ case (x, y) => (/(y), x) }, // r90 = -y,  x
....
)
``````

If you care about the names, I would do this:

``````def genSymmetries(n: Byte, placement: Set[POSITION]): List[Set[POSITION]] = {
def /(x: Byte): Byte = (n - x + 1).toByte

type Transformation = POSITION => POSITION

val id: Transformation = x => x
val r90: Transformation = {
case (x, y) => (/(y), x)
} // -y,  x
...

val transforms = List(id, r90, r180, r270, my, mx, mxy, mxr90)
``````
1 Like

A side note:

``````type POSITION = (Byte, Byte)
``````

That gets erased to (rather heavy):

``````type POSITION = Tuple2[Object, Object]
``````

because Tuple2 isn’t specialized for Bytes https://github.com/scala/scala/blob/2.13.x/src/library/scala/Tuple2.scala

``````final case class Tuple2[@specialized(Int, Long, Double, Char, Boolean/*, AnyRef*/) +T1, @specialized(Int, Long, Double, Char, Boolean/*, AnyRef*/) +T2](_1: T1, _2: T2)
extends Product2[T1, T2]
``````

Solution with a set of named functions https://scastie.scala-lang.org/LZmsBK7YScWWg2K2xNIENw

``````type Position = (Byte, Byte) // erases to heavy Tuple2[Object, Object]

def genSymmetries(n: Byte, placement: Set[Position]): List[Set[Position]] = {
type Transform = (Byte, Byte) => Position
def /(x: Byte): Byte = (n - x + 1).toByte
val id: Transform = (x, y) => (x, y)
val r90: Transform = (x, y) => (/(y), x) // -y,  x
val r180: Transform = (x, y) => (/(x), /(y)) // -x, -y
val r270: Transform = (x, y) => (y, /(x)) //  y, -x
val mx: Transform = (x, y) => (x, /(y)) //  x, -y   mirror about x axis
val my: Transform = (x, y) => (/(x), y) // -x, y    mirror about y axis
val mxy: Transform = (x, y) => (y, x) //  y, x
val mxr90: Transform = (x, y) => (/(y), /(x)) // -y, -x

val transforms: List[(Byte, Byte) => Position] =
List(id, r90, r180, r270, my, mx, mxy, mxr90)

transforms.map { transform =>
val tupledTransform: Position => Position = transform.tupled
placement.map { case p @ (x, y) =>
transform(x, y)
// or if tupling is needed for some reason then
tupledTransform(p)
}
}
}

genSymmetries(5, Set(3.toByte -> 2.toByte)).foreach(println)
``````
3 Likes

Variant:

``````type PosMapping = POSITION => POSITION
val id: PosMapping = identity //  x,  y
val r90: PosMapping = { case (x,y) => (/(y), x) } // -y,  x
// ...
``````

That’s good to know. I was trying to use `Byte` to save memory because the program does an exhaustive search of permutations/combinations to attempt to satisfy a particular relationship. My how was that since my values on only ever between 1 and 10 inclusive, then I could use a Byte to store it. But two `Object`s is sure to be 2x64 bits. Potentially I could use `Char`, but I’m not sure whether I can do arithmetic on `Char`.

OK, so I have to use a `val` rather than a `def`, that was not obvious to me.

No, the names are not important to me. I just used them so I could work out all the useful permutations of x, -x, y, -y.
Before I wrote the functions, I didn’t see the pattern. Now it’s clear and could probably be written more concise. But most of my time was battling to make the numerical addition be Byte addition and not accidentally Integer addition, and battling against binary functions and unary functions taking a Tuple2.

So yeah, I would write all the functions directly in the list.

BTW, about what @tarsa said, the best would be to make your own position class.

``````final case class Position(x: Byte, y: Byte)
``````
1 Like

Thanks for the help guys.

BTW, IntelliJ gets really confused on the indentation here. It seems to ignore the open paren.
That’s depressing. But otherwise, the function is pretty concise now.

``````  def genSymmetries(n: Byte, placement: Set[POSITION]): List[Set[POSITION]] = {
def /(x:Byte):Byte = (n - x + 1).toByte
val transforms = List[POSITION => POSITION](
{case (x,y) => (x,y)},
{case (x,y) => (/(x),y)},
{case (x,y) => (/(x),/(y))},
{case (x,y) => (x,/(y))},
{case (y,x) => (x,y)},
{case (y,x) => (/(x),y)},
{case (y,x) => (/(x),/(y))},
{case (y,x) => (x,/(y))})

transforms.map { tr =>
placement.map(tr)
}
}
``````