This is a cellular automata rule (input Boolean == Left, Center, Right Cell) and output Boolean. What is a better way to represent this in Scala?
trait Rule {
def ruleId() : Int
def rule(inputState:(Boolean, Boolean, Boolean)) : Boolean
override def toString : String = "Rule:" + ruleId
}
class Rule90 extends Rule {
def ruleId() = 90
def rule(inputState:(Boolean, Boolean, Boolean)) : Boolean = {
// Verbose version, show all 8 states
inputState match {
case (true, true, true) => false
case (true, false, true) => false
case (false, true, false) => false
case (false, false, false) => false
case _ => true
}
}
}
One observation... In typical use, you're going to find that the sliding method is the easiest way to feed data into your automata. It works something like this:
scala> val input = Seq(1,2,3,4,5,6,7,8,9)
input: Seq[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> input.sliding(3).toList
res4: List[Seq[Int]] =List(
List(1, 2, 3),
List(2, 3, 4),
...
List(6, 7, 8),
List(7, 8, 9))
To ensure that the number of sequences output by sliding is equal to the number of input elements, you need to pad the input sequence on either side:
scala> (0 +: input :+ 0).sliding(3).toList
res9: List[Seq[Int]] = List(
List(0, 1, 2),
List(1, 2, 3),
...
List(7, 8, 9),
List(8, 9, 0))
Enough of the theory then, back to the code!
For your example (and because I understand something of the underlying problem) I'm padding the sequence with false values here.
Because sliding will output sequences and not tuples, I created the seqYieldsTrue helper method to handle the translation. I also renamed rule to apply, so that your class can be directly used as a function:
trait Rule {
def ruleId: Int //abstract
def yieldsTrue(input: (Boolean,Boolean,Boolean)): Boolean //abstract
override def toString: String = "Rule:" + ruleId
private def seqYieldsTrue(input: Seq[Boolean]) = {
assert(input.size == 3)
input match {
case Seq(a,b,c) => yieldsTrue((a,b,c))
case _ => error("invalid input size")
}
}
def apply(input: Seq[Boolean]) =
(false +: input :+ false).sliding(3) map { seqYieldsTrue }
}
class Rule90 extends Rule {
val ruleId = 90
val falsehoods = Seq(
(true, true, true),
(true, false, true),
(false, true, false),
(false, false, false)
)
def yieldsTrue(input: (Boolean,Boolean,Boolean)) = !falsehoods.contains(input)
}
Then again, I did say I understood the underlying problem! So lets just do away with all these tedious manual rule definitions, and let the compiler generate the lot for us :)
If you don't mind some bit-twiddling...
class WolframAutomata(val ruleId: Int) extends Rule {
def pow2(x: Int) = math.pow(2,x).toInt
def isBitSet(x: Int, bit: Int) = (x & pow2(bit)) > 0
// 8 possible input patterns corresponding to
// different combinations of 3 input bits
val inputs = (0 to 7) map { id =>
Tuple3(
isBitSet(id, 2),
isBitSet(id, 1),
isBitSet(id, 0)
) -> id
} toMap
//each of the 8 input rules corresponds to one bit in the ruleId
val outputs = inputs mapValues { isBitSet(ruleId, _) }
def yieldsTrue(input: (Boolean,Boolean,Boolean)) = outputs(input)
}
(the rule for generating automata from IDs taken from here: http://www.wolframscience.com/nksonline/page-53#previous)
Working like this, you can also roll the logic back up into the Rule trait, as there's little need for a separate abstract trait if there'll only ever be one subclass. You could also safely do away with yieldsTrue in this case and just work directly with the output val. I'll leave that as an exercise to the reader...
Putting it all together (useless REPL output lines removed):
scala> val r90 = new WolframAutomata(90)
r90: WolframAutomata = Rule:90
scala> def destringify(s:String) = s map { case 'X' => true; case _ => false } toSeq
scala> val input = destringify(".......X.......")
scala> val output = Iterator.iterate(input)(r90.apply(_).toSeq) toSeq
scala> def stringify(xs: Seq[Boolean]) = xs map {case true => "X"; case _ => "."} mkString
//can you see what it is yet?
scala> val sierpinski = output.take(10).map(stringify).mkString("\n")
sierpinski: String =
.......X.......
......X.X......
.....X...X.....
....X.X.X.X....
...X.......X...
..X.X.....X.X..
.X...X...X...X.
X.X.X.X.X.X.X.X
...............
...............
Please forgive all the toSeq calls, they're mostly to force evaluation so that you can see some actual output on the REPL, and not just non-empty iterator
Instead of
inputState match {
case (true, true, true) => false
case (true, false, true) => false
case (false, true, false) => false
case (false, false, false) => false
case _ => true
}
you could say
inputState match {
case (true, _, true) | (false, _, false) => false
case _ => true
}
or, simply but maybe not as clearly (depending on purpose/context)
def rule(inputState:(Boolean, Boolean, Boolean)) = inputState._1 != inputState._3
The other answers focused on how to optimize the pattern matching to make it shorter. However, I think that Rule90 might be only an example here. Maybe your question is not how to optimize the pattern matching of rule 90, but if there is a more appropriate way to define the rule type with Scala constructs. Here is my take on that.
First, I wouldn't recommend making subclasses for different rules. You should have one single Rule class, and all the concrete rules would be instances of it. Here would be my definition of the Rule class:
case class Rule(val id:Int, f:PartialFunction[(Boolean,Boolean,Boolean),Boolean])
extends (((Boolean,Boolean,Boolean))=>Boolean) {
def apply(state:(Boolean,Boolean,Boolean)) = f(state)
}
Now, the Rule class is also a proper Scala function. You can instantiate it quite easily, like this:
val rule90 = Rule(90, {
case (true, true, true) => false
case (true, false, true) => false
case (false, true, false) => false
case (false, false, false) => false
case _ => true
})
That's why I chose f to be a PartialFunction, so we can use the Scala syntax for defining partial functions without any overhead, just like this. The disadvantage is that the compiler won't complain in case the match is not exhaustive. You need to make up your mind which is more important to you: code brevity or exhaustive error checking.
If the latter is the case, you can change f to be a Function, by declaring its type as ((Boolean,Boolean,Boolean))=>Boolean. In that case, you would need to declare a specific rule by passing f as a closure to the constructor.
You can apply the Rule function very easily:
val state = (true, false, true)
val newState = rule90(state) // should be false
Also, there are more tricks you can do. Let's say you have all your rules inside a list:
val ruleList = List(rule01, rule02, rule03 /* .... */)
Then, you can for example make a mapping from rule id to rule instance like this:
val rules = ruleList.map(r=>(r.id, r)).toMap
And you could access and use a rule like that:
val state = (true, false, true)
val newState = rules(90)(state)
Or, in order to get all of the next states for all rules:
val state = (true, false, true)
val newStates = rules mapValues _(state)
And access one of the results like this:
val newState_90 = newStates(90)
Pretty cool. However, you can do most of this also with your original Rule definition. I just wanted to play with the idea a little, because I love cellular automata.
You can use extractors to put meaning on the input state values
object EqualLeftAndRight {
def unapply(inputState:(Boolean, Boolean, Boolean)) = inputState._1 == inputState._3
}
def rule(inputState:(Boolean, Boolean, Boolean)) : Boolean =
inputState match {
case EqualLeftAndRight() => true
case _ => false
}
Also, to extend on #Madoc's answer, since you pass a partial function, it doesn't need to cover all cases:
case class Rule(val id:Int)(f:PartialFunction[(Boolean,Boolean,Boolean),Boolean]) extends (((Boolean,Boolean,Boolean))=>Boolean) {
def apply(state:(Boolean,Boolean,Boolean)) = if (f.isDefinedAt(state)) f(state) else false
}
val rule90 = Rule(90) {
case EqualLeftAndRight() => true
}
One additional point, if your ruleIds are meant to be constants, then you can (and should) declare them as vals rather than null-arg defs. Like your defs, the vals defined can be abstract in the trait, and concrete in the class.
trait Rule {
val ruleId : Int
}
class Rule90 extends Rule {
val ruleId= 90
}
Simplified further...
Welcome to Scala version 2.8.0.final (Java HotSpot(TM) Client VM, Java 1.6.0_21).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def rule(inputState:(Boolean, Boolean, Boolean)) = inputState._1 != inputState._3
rule: (inputState: (Boolean, Boolean, Boolean))Boolean
scala> rule((true, false, true))
res0: Boolean = false
scala> rule((true, false, false))
res1: Boolean = true
scala> rule((false, false, false))
res2: Boolean = false
scala> rule((false, true, false))
res3: Boolean = false
scala> rule((false, true, true))
res4: Boolean = true
Oops, sorry, I see #Debilski has this already.
Related
I have a case class (simplified):
case class UserData(name: Option[String], age: Option[String]) {
lazy val nonEmpty = name.isDefined || age.isDefined // TODO
}
Can I replace the current implementation of nonEmpty check using, for instance, Shapeless' HList in order to enumerate all the fields to check that all of them are set to None or at least one has a value?
case class UserData(name: Option[String], age: Option[String]) {
lazy val isEmpty = this.productIterator.forall(_ == None)
}
UserData(None,None).isEmpty
UserData(None,Some("s")).isEmpty
I suppose you want to do different behavior inside case class, if you dont then #pamu answer is what you are looking for.
If you really want to use shapeless you can, but no need.
I think you also check with pure scala using productIterator.
scala> val data = UserData(None, None)
data: UserData = UserData(None,None)
scala> data.productIterator.forall {
| case x: Option[_] => x.isDefined
| case _ => false
| }
res2: Boolean = false
scala> val data = UserData(Some("foo"), Some("bar"))
data: UserData = UserData(Some(foo),Some(bar))
scala> data.productIterator.forall {
| case x: Option[_] => x.isDefined
| case _ => false // you may throw exception if you are not expecting this case
| }
res3: Boolean = true
I would like to add an element depending on the result of a different condition.
As it is now, I did it this way :
val add1 = if(condition1) Seq(ENUM_ELEMENT_1) else Seq()
val add2 = if(condition2) Seq(ENUM_ELEMENT_2) else Seq()
return Seq(add1, add2).flatten
If I was in Java I would just create an empty ArrayList() at the beginning and add to this list as the code encounter the ifs.
But in Scala, I would have to use a mutable object of Seq and I don't know if it's appropriate here.
Declare list of tuples with conditions on left and enums on right:
val conditions: Seq[(Boolean, Enum)] = List(
condition1 -> ENUM_ELEMENT1,
condition2 -> ENUM_ELEMENT2
)
Then you can just reduce it with collect:
val result: Seq[String] = conditions.collect{
case (true, v) => v
}
or flatMap:
val result: Seq[Enum] = conditions.flatMap{
case (true, v) => Some(v)
case _ => None
}
There is several ways to do this. Here's what come out of the blue to me:
(if(condition1) Seq(ENUM_ELEMENT_1) else Seq()) ++ (if(condition2) Seq(ENUM_ELEMENT_2) else Seq())
They are way of factorizing both of this procedure by a function or a fold but it may be overthinking at this state.
Without proper context I am unable to provide a more concrete solution, but I think this pseudo-code represents your problem.
If you have any questions, do not doubt to ask for clarification.
object ListFactory {
type Input = ???
type Output = ???
private val allElements: List[Output] =
List(ENUM_ELEMENT_1, ENUM_ELEMENT_2, ???)
private val conditions: List[Input => Boolean] =
List(???)
def apply(input: Input): List[Output] =
(allElements zip conditions).collect {
case (element, condition) if (condition(input)) => element
}
}
ListFactory(???) // res1: List[Output] = ???
I want to case match tuples which contain boolean values.
Is there an effective way to match the results as case match on boolean looksexhautive
val ABC= "abc"
val DEF = "def"
private def istest1 = true
private def istest2 = true
private def istest3 = true
(istest1, istest2, istest3) match {
case (true, true, true)=>ABC
case (false, true, true) =>DEF
case (false , false , true)=> //print something else
//other cases
}
You need to have a statement for each of the possible outcomes, and using match seems to be the most compact and readable way to do it.
One possible improvement is to use _ for "don't care" values:
(istest1, istest2, istest3) match {
case (true, true, true) => ABC
case (_, true, true) => DEF
case (false, _, true) => //print something
case _ => //other cases
}
There may be performance issues with different versions of these tests, but it is best to pick the one that makes the most sense. Aim for readability and maintainability above perceived performance.
Your approach seems fine, but given all of your values are boolean you could use some stable identifiers to name them and make the code a bit more readable
val ABC = "abc"
val DEF = "def"
def isTest1 = true
def isTest2 = true
def isTest3 = true
val PassedTest1 = true
val PassedTest2 = true
val PassedTest3 = true
val NotPassedTest1 = false
val NotPassedTest2 = false
(isTest1, isTest2, isTest3) match {
case (PassedTest1, PassedTest2, PassedTest3) => ABC
case (NotPassedTest1, _, PassedTest3) => DEF
case (NotPassedTest1, NotPassedTest2, PassedTest3) => //print something
case _ => ???
}
Also as #Tim mentioned, you can use _ to match any value inside the tuple, or to match any tuple as the last case so you don't have to be exaustive
I would even go one step further to Brunos solution:
sealed trait PassedOrNot {
final val Passed = true
final val NotPassed = false
}
case object Test1 extends PassedOrNot
case object Test2 extends PassedOrNot
case object Test3 extends PassedOrNot
def isTest1 = true
def isTest2 = true
def isTest3 = true
(isTest1, isTest2, isTest3) match {
// #formatter:off
case (Test1.Passed , Test2.Passed, Test3.NotPassed) => ???
case (Test1.NotPassed, _ , Test3.NotPassed) => ???
case _ => ???
// #formatter:on
}
I'm trying to write a function myfoo which, taken an Int and a list of ints, verifies if the int element is in the list or not. It should return "true" if the int is in the list, false otherwise.
I've written this function, but when I compile it it returns this error:
error: type mismatch;
found : Unit
required: Boolean
breakable { for (i <-l) {
^
one error found*
This is my program:
import scala.util.control.Breaks._
object findEl extends App{
def myfoo (x:Int,l:List[Int]):Boolean={
breakable { for (i <-l) {
i match {
case a if (a==x) => true
case _ => false
break
}
}
}
}
println(myfoo(1,List(1,2,3,4))) //should print "true"
}
How can I solve it? :)
This is how breakable is implemented
def breakable(op: => Unit) {
try {
op
} catch {
case ex: BreakControl =>
if (ex ne breakException) throw ex
}
}
Breakable returns Unit finally. So thats why compiler is complaining.
Here is one way to fix this. Notice I am using var
import scala.util.control.Breaks._
object findEl extends App {
def myfoo(x: Int, l: List[Int]): Boolean = {
var res: Boolean = false
breakable {
for (i <- l) {
i match {
case a if a == x => res = true
break
case _ => ()
}
}
}
res
}
println(myfoo(1, List(1, 2, 3, 4))) //should print "true"
}
Functional way (better way) of implementing the same
def myFoo(num: Int, list: List[Int]): Boolean = list match {
case Nil => false
case `num` :: xs => true
case _ => myFoo(num, list.tail)
}
Below code is same but does not use back ticks
def myFoo(num: Int, list: List[Int]): Boolean = list match {
case Nil => false
case x :: xs if x == num => true
case _ => myFoo(num, list.tail)
}
Scala REPL
scala> def myFoo(num: Int, list: List[Int]): Boolean = list match {
| case Nil => false
| case `num` :: xs => true
| case _ => myFoo(num, list.tail)
| }
myFoo: (num: Int, list: List[Int])Boolean
scala> myFoo(1, List(2, 1, 2))
res0: Boolean = true
Using breakable is not functional practice
Halting the execution of the program using an exception is not functional. Functional programming advocates communicating through interpretation of types. Internally breakable halts the control flow by throwing exception.
Above second way is the way to solve the problem functionally.
you can use this trick instead
def function myFoo(x:Int, xList:List[Int]) = xList.contains(x)
println(myFoo(1, List(1,2,3,4,5,6)))
I have a list of parameters like List(1,2,3,"abc","c") and a set of functions which validates the data present in the list like isNumberEven, isAValidString etc.
Currently, I take each value of the list and apply proper function which validates the data like isNumberEven(params(0)). This has led to big and messy code which is completely imperative in thinking.
I am expecting that it should be possible to do something like this in Scala -
List(1,2,3,"abc","c").zip(List(fuctions)).foreach{ x => x._2(x._1)}
However, this fails giving a runtime exception of type mismatch:
error: type mismatch;
found : x._1.type (with underlying type Any)
required: Int with String
I tried pattern matching on Function traits but it fails due to type erasure.
Any pointers will be appreciated as how can this be solved.
Very naive and non extensible implementation, I'm not very good with types, surely there's a better way:
val c = List(1,2,3,"abc","c")
def isEven(x: Int) = if(x % 2 == 0) true else false
def isUpperCase(x: String) = if(x.head.isUpper) true else false
c.map {
case x: Int => isEven(x)
case x: String => isUpperCase(x)
case _ => false
}
You could also define list of functions:
scala> val c = List(1,2,3,"abc","c")
c: List[Any] = List(1, 2, 3, abc, c)
scala> def isEven(x: Int) = if(x % 2 == 0) true else false
isEven: (x: Int)Boolean
scala> def isOdd(x: Int) = !isEven(x)
isOdd: (x: Int)Boolean
scala> def isUpperCase(x: String) = if(x.head.isUpper) true else false
isUpperCase: (x: String)Boolean
scala> def someString(x: String) = true
someString: (x: String)Boolean
scala> val ints = List(isEven(_), isOdd(_))
ints: List[Int => Boolean] = List(<function1>, <function1>)
scala> val strings = List(isUpperCase(_), someString(_))
strings: List[String => Boolean] = List(<function1>, <function1>)
scala> c.map {
| case x: Int => ints.map(f => f(x)).exists(f => f(x))
| case x: String => strings.map(f => f(x)).forall(f => f(x))
| case _ => false
| }
res2: List[Boolean] = List(true, true, true, false, false)
I just want to present a different approach without matching, although it is certainly sledgehammer-like.
First all functions are converted to functions of type Any => Boolean.
It iterates over the values in c. For each element it tries to find a function that is applicable and that results in true. If it doesn't find one, false is yielded.
def isEven(i: Int) = i % 2 == 0
def isGreaterThanTwo(i: Int) = i > 2
def hasB(s: String) = s.exists(_ == 'b')
def convert[T](func: T => Boolean) = (a: Any) => func(a.asInstanceOf[T])
val functions = List(isEven _, isGreaterThanTwo _, hasB _)
val c = List(1,2,3,"abc","c")
val result = {
val convertedFunctions = functions.map(convert)
c.map(elem => convertedFunctions.exists(func => Try(func(elem)) getOrElse false))
}
with the result List(false, true, true, true, false).
The upside is that you can have as many functions as you like and it is therefore extensible. The downside is that you rely on exceptions. (which is usually not a good practice)
I first tried a solution with converting to PartialFunction and modifying the isDefined methods so it can be called on Any but then checks for a certain type. Then a lot of type-erasure happened and I couldn't make it work. Maybe that could be worth a shot.
If that is possible the code could be changed to:
def convert[T](func: T => Boolean) = new PartialFunction[Any, Boolean] {
def isDefinedAt(x : Any) = ??? //check if x is an instance of T, type erasure problem
def apply(x : Any) = func(x.asInstanceOf[T])
}
val result = {
val convertedFunctions = functions.map(convert)
c.map(elem => convertedFunctions.exists(func =>
func.isDefinedAt(elem) && func(elem)))
}
which looks pretty nice.
I'm not entirely certain on how you're planning on using the data afterwards, because 'foreach' would not actually return anything. But maybe this pattern-matched solution can help you achieve what you want?
scala> val f1 = (x:Int) => false
f1: Int => Boolean = <function1>
scala> val f2 = (x:String) => true
f2: String => Boolean = <function1>
scala> List(1,2,3,"abc","c").map {
case x:String => f2(x)
case x:Int => f1(x)
}
res3: List[Boolean] = List(false, false, false, true, true)