| (true, Select(true)) => true
| (false, Select(false)) => false
How can I combine these two in a switch statement with generic type?
Unfortunately the patterns that you match against in a switch statement have to be 'linear' (ie, the variants inside the patterns should only appear once):
See https://caml.inria.fr/pub/docs/oreilly-book/html/book-ora016.html
A pattern must necessarily be linear, that is, no given variable can occur more than once inside the pattern being matched. Thus, we might have hoped to be able to write:
# let equal c = match c with
(x,x) -> true
| (x,y) -> false;; Characters 35-36: This variable is bound several times in this matching
But this would have required the compiler to know how to carry out
equality tests. Yet this immediately raises numerous problems. If we
accept physical equality between values, we get a system which is too
weak, incapable of recognizing the equality between two occurrences of
the list [1; 2], for example. If we decide to use structural equality,
we run the risk of having to traverse, ad infinitum, circular
structures.
Note that ReasonML is just an alternative syntax for OCaml, so the above also holds for Reason. match is just the OCaml version of switch.
It is possible to combine the two cases generically using a when guard:
let f = (a, b) =>
switch (a, b) {
| (a, Select(b)) when a == b => a
};
However, note that this isn't exhaustive, and you haven't specified what should be returned in the case that a != b. To avoid the non-exhaustiveness warning, and crash at runtime, you need to add another case to cover that.
Yeah this is doable:
// using switch
let theSolution = x => switch(x) {
| (_, Select(inside)) => inside
};
// using `fun`
let theSolution = x => x |> fun | (_, Select(inside)) => inside;
// or for a super short solution:
let theSolution = fun | (_, Select(inside)) => inside;
For example:
type select = | Select(bool);
let a = (true, Select(true));
let b = (true, Select(false));
let c = (false, Select(true));
let d = (false, Select(false));
let theSolution = x => x |> fun | (_, Select(inside)) => inside;
Js.log2("A is", theSolution(a));
Js.log2("B is", theSolution(b));
Js.log2("C is", theSolution(c));
Js.log2("D is", theSolution(d));
Will result in:
"A is" true
"B is" false
"C is" true
"D is" false
Or if you want to compare the booleans, you can do either of:
let theSolution = fun | (a, Select(b)) => a && b;
let theSolution = fun | (a, Select(b)) => a == b;
See this example in the online repl
Following can be a solution for your problem. The operation a&&b depends on what logic you want the block to follow. I took a reasonable assumption that you wanted to perform AND operation. If you provide other possible conditions then this can be refined.
let getSelectionResponse = x => switch(x){ | (a, Select(b)) => a&&b};
Tried it here
Related
I'm working on some homework and I need to create a function that checks if a value exists in a list. If it does it will return true, otherwise it returns false. I have an idea of how to do it but I keep getting errors. I think it may be due to my lack of knowledge of syntax and style as this is my first time coding in sml.
I created the function exist and am passing a value and list in as a tuple.
fun exist (x, []) =
if x = hd ([]) then true
else if x = tl ([]) then true
else false;
Sorry if this code is laughably incorrect but I get the error message:
" stdIn:2.6 Warning: calling polyEqual
stdIn:3.11 Warning: calling polyEqual
stdIn:1.6-4.11 Warning: match nonexhaustive
(x,nil) => ...
val exist = fn : ''a list * 'b list -> bool "
and I'm not really sure how to fix this. Any help would be great.
Your function is pattern-matching on [], so it can only ever match the empty list.
Also, hd [] and tl [] are both errors since the empty list has neither head nor tail.
Further, if some_condition then true else false is equivalent to some_condition.
(And if some_condition then false else true is equivalent to not some_condition.)
Logical expressions are usually more readable than chains of conditionals.
And you forgot to recurse; you need to use exist on the tail of the list if the first element is not what you're looking for.
Either stick to pattern matching:
fun exist (_, []) = false
| exist (x, y::ys) = x = y orelse exist (x, ys)
or don't use it:
fun exist (x, xs) = not (null xs) andalso (x = hd xs orelse exist (x, tl xs))
Pattern matching is often the most readable solution and gives a clear picture of the various cases.
(You seem to have mixed the two forms, treating [] as an identifier rather than a type constructor.)
Functional programming style of coding guideline says we should not use null or var in Scala for better functional programming code.
I want to perform some operation like below
var a = 2
if(condition==true){
a = a * 3 /*someOperation*/
}
if(condition2==true){
a = a * 6 /*someOperation*/
}
if(condition3==true){
a = a * 8 /*someOperation*/
}
val b = a * 2/*someOperation*/
So now how to avoid var in this condition and replace it with val?
The simplest way to avoid var with multiple conditions is to use temporary values
val a1 = 2
val a2 = if (condition) a1*3 else a1
val a3 = if (condition2) a2*6 else a2
val a = if (condition3) a3*8 else a3
val b = a * 2/*someOperation*/
In the real code you would give a1, a2, and a3 meaningful names to describe the result of each stage of processing.
If you are bothered about having these extra values in scope, put it in a block:
val a = {
val a1 = 2
val a2 = if (condition) a1*3 else a1
val a3 = if (condition2) a2*6 else a2
if (condition3) a3*8 else a3
}
Update
If you want a more functional approach, collect the conditions and modifications together and apply them in turn, like this:
val mods: List[(Boolean, Int=>Int)] = List(
(condition, _*3),
(condition2, _*6),
(condition3, _*8)
)
val a = mods.foldLeft(2){ case (a,(cond, mod)) => if (cond) mod(a) else a }
This is really only appropriate when either the conditions or the modifications are more complex, and keeping them together makes the code clearer.
val a = 2 * (if (condition) 3 else 1)
val b = 2 * a
Or, perhaps...
val a = 2
val b = 2 * (if (condition) a*3 else a)
It depends on if/how a is used after these operations.
I think you might have oversimplified your example, because we know the value of a when writing the code so you could just write it out like this:
val a = if (condition) 2 else 6
val b = a * 2
Assuming your real operation is more complex and can't be precalculated like that, then you might find a pattern match like this is a nicer way to do it:
val a = (condition, 2) match {
case (true, z) =>
z * 3
case (false, z) =>
z
}
val b = a * 2
You can try the following approach:
type Modification = Int => Int
type ModificationNo = Int
type Conditions = Map[ModificationNo, Boolean]
val modifications: List[(Modification, ModificationNo)] =
List[Modification](
a => a * 3,
a => a * 6,
a => a * 8
).zipWithIndex
def applyModifications(initial: Int, conditions: Conditions): Int =
modifications.foldLeft[Int](initial) {
case (currentA, (modificationFunc, modificationNo)) =>
if (conditions(modificationNo)) modificationFunc(currentA)
else currentA
}
val a: Int = applyModifications(initial = 2,
conditions = Map(0 -> true, 1 -> false, 2 -> true))
It may look complicated but this approach allows additional flexibility if number of conditions is big enough.
Now when you have to add more conditions, you don't need to write new if-statements and further reassignments to var. Just add a modification function to an existing list of
there is no 1 perfect solution.
sometimes it is ok to use var if it simplifies the code and limited in scope of a single function.
that being said, this is how I would do it in functional way:
val op1: Int => Int =
if (condition1) x => x * 3
else identity
val op2: Int => Int =
if (condition2) x => x * 6
else identity
val op3: Int => Int =
if (condition3) x => x * 8
else identity
val op = op1 andThen op2 andThen op3
// can also be written as
// val op = Seq(op1, op2, op3).reduceLeft(_ andThen _)
val a = 2
val b = op(a) * 2
The easiest way it to wrap your variable into a monad, so that you .map over it. The simplest monad is an Option, so you could write:
val result = Option(a).map {
case a if condition => a*2
case a => a
}.map {
case a if condition2 => a*6
case a => a
}.fold(a) {
case a if condition3 => a*8
case a => a
}
(The last operation is fold instead of map so that you end up with the "raw" value for the result, rather than an option. Equivalently, you could write it as a .map, and then add .getOrElse(a) at the end).
When you have many conditional operations like this, or many use cases where you have to repeat the pattern, it might help to put them into a list, and then traverse that list instead:
def applyConditionals[T](toApply: (() => Boolean, T => T)*) = toApply
.foldLeft(a) {
case (a, (cond, oper)) if cond() => oper(a)
case (a, _) => a
}
val result = applyConditionals[Int] (
(() => condition, _ * 2),
(() => condition2, _ * 6),
(() => condition3, _ * 8)
)
The important point is that FP is a whole new paradigm of programming. Its so fundamentally different that sometimes you can not take an excerpt of imperative code and try to convert it to functional code.
The difference applies not just to code but to the way of thinking towards solving a problem. Functional programming requires you to think in terms of chained mathematical computation which are more or less independent of each other (which means that each of these mathematical computation should not be changing anything outside of its own environment).
Functional programming totally avoids mutation of state. So, if your solution has a requirement to have a variable x which has a value 10 at one point and other value 100 at some other point... then your solution is not functional. And you can not write function code for a solution which is not functional.
Now, if you look at your case (assuming you do not actually need a to be 2 and then change to 6 after sometime) and try to convert it into chain of independent mathematical computation, then the simplest one is following,
val a = if (condition) 2 else 6
val b = a * 2
Scala requires pattern variables to be linear, i.e. pattern
variable may not occur more than once in a pattern. Thus, this example does not compile:
def tupleTest(tuple: (Int, Int)) = tuple match {
case (a, a) => a
case _ => -1
}
But you can use two pattern variables and a guard to check equality instead:
def tupleTest(tuple: (Int, Int)) = tuple match {
case (a, b) if a == b => a
case _ => -1
}
So why does Scala require pattern variables to be linear? Are there any cases that can not be transformed like this?
Edit
It is easy to transform the first example into the second (Scala to Scala). Of all occurrences of a variable v in the pattern take the expressions that is evaluated first and assign it to the variable v. For each other occurrence introduce a new variable with a name that is not used in the current scope. For each of those variables v' add a guard v == v'. It is the same way a programmer would go (=> same efficiency). Is there any problem with this approach? I'd like to see an example that can not be transformed like this.
Because case (a, b) is basically assigning val a to _._1 and val b to _._2 (at least you can view it like that). In case of case (a, a), you cannot assign val a to both _._1 and _._2.
Actually the thing you want to do would have been looked like
case (a, `a`) => ???
as scala uses backtick to match an identifier. But unfortunately that still doesn't work as the visibility of a is given only after => (would have been fun though, I also hate writing case (a, b) if a = b =>). And the reason of this is probably just because it is harder to write a compiler that supports that
In the following code snippet in which the outer match vars (x,y) are case matched by (xx,yy):
scala> val (x,y) = (1,2)
x: Int = 1
y: Int = 2
scala> (x,y) match {
| case (xx:Int, yy:Int) => println(s"x=$x xx=$xx")
| }
x=1 xx=1
We could have also written that code as follows:
scala> (x,y) match {
| case (x:Int, y:Int) => println(s"x=$x y=$y")
| }
x=1 y=2
In this latter case the Scala Code Analyzers will inform us:
Suspicious shadowing by a Variable Pattern
OK. But is there any situation where we could end up actually misusing the inner variable (x or y) in place of the original outer match variables?
It seems this is purely stylistic? No actual possibility for bugs? If so i would be interested to learn what the bugs could be.
This could be confusing:
val x = Some(1)
val y = Some(2)
(x, y) match {
case (Some(x), Some(y)) => println(s"x=$x y=$y")
}
x and y have different types depending on whether you are inside or outside of the match. If this code wasn't using simply Option, and was several lines longer, it could be rather difficult to reason about.
Could any bugs arise from this? None that I can think of that aren't horribly contrived. You could for example, mistake one for another.
val list = List(1,2,3)
list match {
case x :: y :: list => list // List(3) and not List(1,2,3)
case x :: list => list // List with 1 element, should the outer list have size 2
case _ => list // Returns the outer list when empty
}
Not to mention what a horrible mess that is. Within the match, list sometimes refers to an inner symbol, and sometimes the outer list.
It's just code that's unnecessarily complicated to read and understand, there are no special bugs that could happen.
Apart from:
case class A
... case which is quite useful?
Why do we need to use case in match? Wouldn't:
x match {
y if y > 0 => y * 2
_ => -1
}
... be much prettier and concise?
Or why do we need to use case when a function takes a tuple? Say, we have:
val z = List((1, -1), (2, -2), (3, -3)).zipWithIndex
Now, isn't:
z map { case ((a, b), i) => a + b + i }
... way uglier than just:
z map (((a, b), i) => a + b + i)
...?
First, as we know, it is possible to put several statements for the same case scenario without needing some separation notation, just a line jump, like :
x match {
case y if y > 0 => y * 2
println("test")
println("test2") // these 3 statements belong to the same "case"
}
If case was not needed, compiler would have to find a way to know when a line is concerned by the next case scenario.
For example:
x match {
y if y > 0 => y * 2
_ => -1
}
How compiler would know whether _ => -1 belongs to the first case scenario or represents the next case?
Moreover, how compiler would know that the => sign doesn't represent a literal function but the actual code for the current case?
Compiler would certainly need a kind of code like this allowing cases isolation:
(using curly braces, or anything else)
x match {
{y if y > 0 => y * 2}
{_ => -1} // confusing with literal function notation
}
And surely, solution (provided currently by scala) using case keyword is a lot more readable and understandable than putting some way of separation like curly braces in my example.
Adding to #Mik378's answer:
When you write this: (a, b) => something, you are defining an anonymous Function2 - a function that takes two parameters.
When you write this: case (a, b) => something, you are defining an anonymous PartialFunction that takes one parameter and matches it against a pair.
So you need the case keyword to differentiate between these two.
The second issue, anonymous functions that avoid the case, is a matter of debate:
https://groups.google.com/d/msg/scala-debate/Q0CTZNOekWk/z1eg3dTkCXoJ
Also: http://www.scala-lang.org/old/node/1260
For the first issue, the choice is whether you allow a block or an expression on the RHS of the arrow.
In practice, I find that shorter case bodies are usually preferable, so I can certainly imagine your alternative syntax resulting in crisper code.
Consider one-line methods. You write:
def f(x: Int) = 2 * x
then you need to add a statement. I don't know if the IDE is able to auto-add parens.
def f(x: Int) = { val res = 2*x ; res }
That seems no worse than requiring the same syntax for case bodies.
To review, a case clause is case Pattern Guard => body.
Currently, body is a block, or a sequence of statements and a result expression.
If body were an expression, you'd need braces for multiple statements, like a function.
I don't think => results in ambiguities since function literals don't qualify as patterns, unlike literals like 1 or "foo".
One snag might be: { case foo => ??? } is a "pattern matching anonymous function" (SLS 8.5). Obviously, if the case is optional or eliminated, then { foo => ??? } is ambiguous. You'd have to distinguish case clauses for anon funs (where case is required) and case clauses in a match.
One counter-argument for the current syntax is that, in an intuition deriving from C, you always secretly hope that your match will compile to a switch table. In that metaphor, the cases are labels to jump to, and a label is just the address of a sequence of statements.
The alternative syntax might encourage a more inlined approach:
x match {
C => c(x)
D => d(x)
_ => ???
}
#inline def c(x: X) = ???
//etc
In this form, it looks more like a dispatch table, and the match body recalls the Map syntax, Map(a -> 1, b -> 2), that is, a tidy simplification of the association.
One of the key aspects of code readability is the words that grab your attention. For example,
return grabs your attention when you see it because you know that it is such a decisive action (breaking out of the function and possible sending a value back to the caller).
Another example is break--not that I like break, but it gets your attention.
I would agree with #Mik378 that case in Scala is more readable than the alternatives. Besides the compiler confusion he mentions, it gets your attention.
I am all for concise code, but there is a line between concise and illegible. I will gladly make the trade of 4n characters (where n is the number of cases) for the substantial readability that I get in return.