Matching user combinations / operators

I know that you can do list matching in ways like

val list = List(1,2,3) list match { case head::tail => head case _ => //whatever } 

so I started to wonder how it works. If I understand correctly, :: is just an operator, so to stop me from doing something like

 4 match { case x + 2 => x //I would expect x=2 here } 

If there is a way to create such functionality, how to do it; if not, why?

+6
source share
3 answers

Matching the pattern takes input and decomposes it using the unapply function. Thus, in your case, unapply(4) will have to return two numbers, the sum of which is 4. However, there are many pairs that add up to 4, so the function does not know what to do.

You need 2 be available for unapply function. For this, the special case class will work, in which 2 is stored:

 case class Sum(addto: Int) { def unapply(i: Int) = Some(i - addto) } val Sum2 = Sum(2) val Sum2(x) = 5 // x = 3 

(It would be nice to do something like val Sum(2)(y) = 5 for compactness, but Scala does not allow parameterizing extractors, see here ).

[EDIT: This is a little silly, but you can do the following too:

 val `2 +` = Sum(2) val `2 +`(y) = 5 // y = 3 

]

EDIT: The reason head::tail works is because there is one way to split the head into the tail of a list.

There is nothing special about :: versus + : you could use + if you had a predetermined idea of ​​how you wanted it to break the number. For example, if you want + mean "split in half," you could do something like:

 object + { def unapply(i: Int) = Some(ii/2, i/2) } 

and use it like:

 scala> val a + b = 4 a: Int = 2 b: Int = 2 scala> val c + d = 5 c: Int = 3 d: Int = 2 

EDIT: Finally, this explains that when matching pattern A op B means the same as op(A,B) , which makes the syntax nice.

+8
source

Matching with case head :: tail uses the infix operation pattern of the form p1 op p2 , which translates to op(p1, p2) before performing the actual mapping. ( API for ::

The problem with + is this:

Easy to add

 object + { def unapply(value: Int): Option[(Int, Int)] = // ... } 

which will perform the mapping, you can provide only one result per value. For instance.

 object + { def unapply(value: Int): Option[(Int, Int)] = value match { case 0 => Some(0, 0) case 4 => Some(3, 1) case _ => None } 

Now it works:

 0 match { case x + 0 => x } // returns 0 

also this

 4 match { case x + 1 => x } // returns 3 

But it will not, and you cannot change it:

 4 match { case x + 2 => x } // does not match 

There is no problem for :: , though, because it is always determined what the head and what the tail list is.

+4
source

Scala has two :: (pronounced "cons"). One of them is an operator on a List , and the other is a class, which is a non-empty list characterized by a head and a tail. Thus, head :: tail is a constructor template that has nothing to do with the operator.

+1
source

Source: https://habr.com/ru/post/893012/


All Articles