- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
strange head :: tail pattern matching
Thu, 2011-06-16, 17:20
This result was unexpected for me. I get with both scala versions 2.8.1 and 2.9.0.1. Shouldn't I expect to match head :: tail in the first example? Why should x.toSeq fail to match, but x.toList match?
Thanks, John
scala> def foo(x: Int*) = x.toSeq match { case Nil => println("nil"); case head :: tail => println("headtail"); }
foo: (x: Int*)Unit
scala> foo(1)
scala.MatchError: WrappedArray(1)
at .foo(<console>:8)
at .<init>(<console>:10)
at .<clinit>(<console>)
at RequestResult$.<init>(<console>:9)
at RequestResult$.<clinit>(<console>)
at RequestResult$scala_repl_result(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
at scala.util.control.Exception$Catch.apply(Exception.sca...
scala> def foo(x: Int*) = x.toList match { case Nil => println("nil"); case head :: tail => println("headtail"); }
foo: (x: Int*)Unit
scala> foo(1)
headtail
scala> Seq(1) match { case Nil => println("nil"); case head :: tail => println("headtail"); }
headtail
scala>
--
There are more things in heaven and earth, Horatio,
Than are dreamt of in your philosophy.
Thanks, John
scala> def foo(x: Int*) = x.toSeq match { case Nil => println("nil"); case head :: tail => println("headtail"); }
foo: (x: Int*)Unit
scala> foo(1)
scala.MatchError: WrappedArray(1)
at .foo(<console>:8)
at .<init>(<console>:10)
at .<clinit>(<console>)
at RequestResult$.<init>(<console>:9)
at RequestResult$.<clinit>(<console>)
at RequestResult$scala_repl_result(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
at scala.util.control.Exception$Catch.apply(Exception.sca...
scala> def foo(x: Int*) = x.toList match { case Nil => println("nil"); case head :: tail => println("headtail"); }
foo: (x: Int*)Unit
scala> foo(1)
headtail
scala> Seq(1) match { case Nil => println("nil"); case head :: tail => println("headtail"); }
headtail
scala>
--
There are more things in heaven and earth, Horatio,
Than are dreamt of in your philosophy.
Thu, 2011-06-16, 18:17
#2
Re: strange head :: tail pattern matching
To expand on this, "Seq" is abstract, while "List" is one concrete
implementation of it. So Seq(1) may produce a List, as well as it
might have produced a Vector -- as Alec said, you lucked out there.
As for "x.toSeq", it just so happens that "x" was a Seq to begin with,
so it just returned itself -- itself being something that was not a
List.
On Thu, Jun 16, 2011 at 13:30, Alec Zorab wrote:
> It says right there in the error!
>
> scala.MatchError: WrappedArray(1) doesn't match head :: tail, nor does
> it match nil. That's because both of those are list patterns, and a
> list isn't an array.
>
> Seq(1) happens to make a List, by happy co-incidence. If it made an
> array you'd be out of luck.
>
> You probably want to use this:
>
> def foo(x: Int*) = x.toList match { case Nil => println("nil"); case
> head :: tail => println("headtail"); }
>
> which actually works!
>
> On Thu, Jun 16, 2011 at 5:20 PM, john sullivan wrote:
>> This result was unexpected for me. I get with both scala versions 2.8.1 and
>> 2.9.0.1. Shouldn't I expect to match head :: tail in the first example? Why
>> should x.toSeq fail to match, but x.toList match?
>> Thanks, John
>>
>> scala> def foo(x: Int*) = x.toSeq match { case Nil => println("nil"); case
>> head :: tail => println("headtail"); }
>> foo: (x: Int*)Unit
>>
>> scala> foo(1)
>>
>> scala.MatchError: WrappedArray(1)
>> at .foo(:8)
>> at .(:10)
>> at .()
>> at RequestResult$.(:9)
>> at RequestResult$.()
>> at RequestResult$scala_repl_result()
>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>> at
>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>> at
>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>> at java.lang.reflect.Method.invoke(Method.java:597)
>> at
>> scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
>> at
>> scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
>> at scala.util.control.Exception$Catch.apply(Exception.sca...
>> scala> def foo(x: Int*) = x.toList match { case Nil => println("nil"); case
>> head :: tail => println("headtail"); }
>> foo: (x: Int*)Unit
>>
>> scala> foo(1)
>>
>> headtail
>>
>> scala> Seq(1) match { case Nil => println("nil"); case head :: tail =>
>> println("headtail"); }
>> headtail
>>
>> scala>
>>
>> --
>> There are more things in heaven and earth, Horatio,
>> Than are dreamt of in your philosophy.
>>
>
Thu, 2011-06-16, 19:07
#3
Re: strange head :: tail pattern matching
I had a similar question about string. I'd like to match on the first
character of a string and the rest. I know how to do this a sightly
more ugly way but it would be nice to have a elegent solution like
str match {
case first :: rest => ...
...
}
Without converting the string to a list.
On Jun 16, 10:07 am, Daniel Sobral wrote:
> To expand on this, "Seq" is abstract, while "List" is one concrete
> implementation of it. So Seq(1) may produce a List, as well as it
> might have produced a Vector -- as Alec said, you lucked out there.
>
> As for "x.toSeq", it just so happens that "x" was a Seq to begin with,
> so it just returned itself -- itself being something that was not a
> List.
>
>
>
>
>
>
>
>
>
> On Thu, Jun 16, 2011 at 13:30, Alec Zorab wrote:
> > It says right there in the error!
>
> > scala.MatchError: WrappedArray(1) doesn't match head :: tail, nor does
> > it match nil. That's because both of those are list patterns, and a
> > list isn't an array.
>
> > Seq(1) happens to make a List, by happy co-incidence. If it made an
> > array you'd be out of luck.
>
> > You probably want to use this:
>
> > def foo(x: Int*) = x.toList match { case Nil => println("nil"); case
> > head :: tail => println("headtail"); }
>
> > which actually works!
>
> > On Thu, Jun 16, 2011 at 5:20 PM, john sullivan wrote:
> >> This result was unexpected for me. I get with both scala versions 2.8.1 and
> >> 2.9.0.1. Shouldn't I expect to match head :: tail in the first example? Why
> >> should x.toSeq fail to match, but x.toList match?
> >> Thanks, John
>
> >> scala> def foo(x: Int*) = x.toSeq match { case Nil => println("nil"); case
> >> head :: tail => println("headtail"); }
> >> foo: (x: Int*)Unit
>
> >> scala> foo(1)
>
> >> scala.MatchError: WrappedArray(1)
> >> at .foo(:8)
> >> at .(:10)
> >> at .()
> >> at RequestResult$.(:9)
> >> at RequestResult$.()
> >> at RequestResult$scala_repl_result()
> >> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> >> at
> >> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
> >> at
> >> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> >> at java.lang.reflect.Method.invoke(Method.java:597)
> >> at
> >> scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
> >> at
> >> scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
> >> at scala.util.control.Exception$Catch.apply(Exception.sca...
> >> scala> def foo(x: Int*) = x.toList match { case Nil => println("nil"); case
> >> head :: tail => println("headtail"); }
> >> foo: (x: Int*)Unit
>
> >> scala> foo(1)
>
> >> headtail
>
> >> scala> Seq(1) match { case Nil => println("nil"); case head :: tail =>
> >> println("headtail"); }
> >> headtail
>
> >> scala>
>
> >> --
> >> There are more things in heaven and earth, Horatio,
> >> Than are dreamt of in your philosophy.
>
> --
> Daniel C. Sobral
>
> I travel to the future all the time.
Thu, 2011-06-16, 19:17
#4
Re: Re: strange head :: tail pattern matching
On Thu, Jun 16, 2011 at 10:57 AM, Joshua Gooding <skavookie [at] gmail [dot] com> wrote:
scala> val StringMatcher = "(.)(.*)".rStringMatcher: scala.util.matching.Regex = (.)(.*)
scala> val StringMatcher(first,rest) = "hello" // throws MatchError at the drop of a hatfirst: String = hrest: String = ello
// or more verbose...
someString match { case StringMatcher(first,rest) => doStuff(first,rest) case other => whoops(first,rest)}
-0xe1a
I had a similar question about string. I'd like to match on the first
character of a string and the rest. I know how to do this a sightly
more ugly way but it would be nice to have a elegent solution like
str match {
case first :: rest => ...
...
}
Without converting the string to a list.
scala> val StringMatcher = "(.)(.*)".rStringMatcher: scala.util.matching.Regex = (.)(.*)
scala> val StringMatcher(first,rest) = "hello" // throws MatchError at the drop of a hatfirst: String = hrest: String = ello
// or more verbose...
someString match { case StringMatcher(first,rest) => doStuff(first,rest) case other => whoops(first,rest)}
-0xe1a
Thu, 2011-06-16, 19:27
#5
Re: Re: strange head :: tail pattern matching
This is a bit nicer:
scala> "hello".toSeq match { | case Seq(first,rest@_*) => (first,rest) | }res3: (Char, Seq[Char]) = (h,ello)
scala> "hello".toSeq res4: Seq[Char] = hello
scala> res4.getClassres5: java.lang.Class[_] = class scala.collection.immutable.WrappedString
-0xe1a
On Thu, Jun 16, 2011 at 11:12 AM, Alex Cruise <alex [at] cluonflux [dot] com> wrote:
scala> "hello".toSeq match { | case Seq(first,rest@_*) => (first,rest) | }res3: (Char, Seq[Char]) = (h,ello)
scala> "hello".toSeq res4: Seq[Char] = hello
scala> res4.getClassres5: java.lang.Class[_] = class scala.collection.immutable.WrappedString
-0xe1a
On Thu, Jun 16, 2011 at 11:12 AM, Alex Cruise <alex [at] cluonflux [dot] com> wrote:
scala> val StringMatcher = "(.)(.*)".rStringMatcher: scala.util.matching.Regex = (.)(.*)
scala> val StringMatcher(first,rest) = "hello" // throws MatchError at the drop of a hatfirst: String = hrest: String = ello
// or more verbose...
someString match { case StringMatcher(first,rest) => doStuff(first,rest) case other => whoops(first,rest)}
-0xe1a
Fri, 2011-06-17, 01:47
#6
Re: strange head :: tail pattern matching
Okay, thanks Alec. Now I see that :: method belongs to List, and not Seq, even though Seq has head and tail. I've been typing things as Seq in an attempt to prefer abstract types over specific implementations, but I guess that's not always the best thing. But wait, wouldn't it make sense to define the :: "unapply" thingie on LinearSeq? LinearSeq subclasses are supposed to have efficient head and tail methods. The :: match operation fails on class Stack (which subclasses LinearSeq) with a different error:
scala> val a = new scala.collection.immutable.Stack[Int]()a: scala.collection.immutable.Stack[Int] = Stack()
scala> a match { case head :: tail => println("headtail"); } <console>:7: error: constructor cannot be instantiated to expected type; found : collection.immutable.::[B] required: scala.collection.immutable.Stack[Int] a match { case head :: tail => println("headtail"); } ^
scala>
Thanks Alec.
Best, John
On Thu, Jun 16, 2011 at 12:30 PM, Alec Zorab <aleczorab [at] googlemail [dot] com> wrote:
--
There are more things in heaven and earth, Horatio,
Than are dreamt of in your philosophy.
scala> val a = new scala.collection.immutable.Stack[Int]()a: scala.collection.immutable.Stack[Int] = Stack()
scala> a match { case head :: tail => println("headtail"); } <console>:7: error: constructor cannot be instantiated to expected type; found : collection.immutable.::[B] required: scala.collection.immutable.Stack[Int] a match { case head :: tail => println("headtail"); } ^
scala>
Thanks Alec.
Best, John
On Thu, Jun 16, 2011 at 12:30 PM, Alec Zorab <aleczorab [at] googlemail [dot] com> wrote:
It says right there in the error!
scala.MatchError: WrappedArray(1) doesn't match head :: tail, nor does
it match nil. That's because both of those are list patterns, and a
list isn't an array.
Seq(1) happens to make a List, by happy co-incidence. If it made an
array you'd be out of luck.
You probably want to use this:
def foo(x: Int*) = x.toList match { case Nil => println("nil"); case
head :: tail => println("headtail"); }
which actually works!
On Thu, Jun 16, 2011 at 5:20 PM, john sullivan <sullymandias [at] gmail [dot] com> wrote:
> This result was unexpected for me. I get with both scala versions 2.8.1 and
> 2.9.0.1. Shouldn't I expect to match head :: tail in the first example? Why
> should x.toSeq fail to match, but x.toList match?
> Thanks, John
>
> scala> def foo(x: Int*) = x.toSeq match { case Nil => println("nil"); case
> head :: tail => println("headtail"); }
> foo: (x: Int*)Unit
>
> scala> foo(1)
>
> scala.MatchError: WrappedArray(1)
> at .foo(<console>:8)
> at .<init>(<console>:10)
> at .<clinit>(<console>)
> at RequestResult$.<init>(<console>:9)
> at RequestResult$.<clinit>(<console>)
> at RequestResult$scala_repl_result(<console>)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
> at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> at java.lang.reflect.Method.invoke(Method.java:597)
> at
> scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
> at
> scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
> at scala.util.control.Exception$Catch.apply(Exception.sca...
> scala> def foo(x: Int*) = x.toList match { case Nil => println("nil"); case
> head :: tail => println("headtail"); }
> foo: (x: Int*)Unit
>
> scala> foo(1)
>
> headtail
>
> scala> Seq(1) match { case Nil => println("nil"); case head :: tail =>
> println("headtail"); }
> headtail
>
> scala>
>
> --
> There are more things in heaven and earth, Horatio,
> Than are dreamt of in your philosophy.
>
--
There are more things in heaven and earth, Horatio,
Than are dreamt of in your philosophy.
Fri, 2011-06-17, 01:57
#7
Re: strange head :: tail pattern matching
On Thu, Jun 16, 2011 at 6:41 PM, john sullivan wrote:
> Okay, thanks Alec. Now I see that :: method belongs to List, and not Seq,
> even though Seq has head and tail. I've been typing things as Seq in an
> attempt to prefer abstract types over specific implementations, but I guess
> that's not always the best thing. But wait, wouldn't it make sense to define
> the :: "unapply" thingie on LinearSeq? LinearSeq subclasses are supposed to
> have efficient head and tail methods. The :: match operation fails on class
> Stack (which subclasses LinearSeq) with a different error:
While :: is a method on List, it is also the actual class for a list as well:
https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_0_1/src//lib...
The :: unapply thingie isn't actually defined anywhere, it is
automatically generated because :: is a case class.
Fri, 2011-06-17, 02:17
#8
Re: strange head :: tail pattern matching
On Thu, Jun 16, 2011 at 5:41 PM, john sullivan <sullymandias [at] gmail [dot] com> wrote:
Call me Alex please. :)
It is true that Seq has head and tail methods, but they're not used when you say case Seq(hd, tl @ _*). In that case you're using special pattern matching syntax that relies on the unapplySeq method on Seq's companion object.
case Seq(x,y,z) will match any Seq that's exactly three elements long, and bind those elements to x,y,z respectively.
case Seq(x, xs @ _*) will match any Seq that's at least one element long, bind the first element to x, and the remaining subsequence to xs.
Note that unapplySeq can't make heads or tails of anything (haw!), it's the pattern matcher that's cracking open the sequence and binding elements.
On the contrary, one should still use the most general applicable type in one's APIs. It's just that pattern matching on lists is so nice... :)
It would be nice indeed, but I'm sure there are all kinds of subtle reasons why it's better not to. :)
-0xe1a
Okay, thanks Alec. Now I see that :: method belongs to List, and not Seq, even though Seq has head and tail.
Call me Alex please. :)
It is true that Seq has head and tail methods, but they're not used when you say case Seq(hd, tl @ _*). In that case you're using special pattern matching syntax that relies on the unapplySeq method on Seq's companion object.
case Seq(x,y,z) will match any Seq that's exactly three elements long, and bind those elements to x,y,z respectively.
case Seq(x, xs @ _*) will match any Seq that's at least one element long, bind the first element to x, and the remaining subsequence to xs.
Note that unapplySeq can't make heads or tails of anything (haw!), it's the pattern matcher that's cracking open the sequence and binding elements.
I've been typing things as Seq in an attempt to prefer abstract types over specific implementations, but I guess that's not always the best thing.
On the contrary, one should still use the most general applicable type in one's APIs. It's just that pattern matching on lists is so nice... :)
But wait, wouldn't it make sense to define the :: "unapply" thingie on LinearSeq? LinearSeq subclasses are supposed to have efficient head and tail methods. The :: match operation fails on class Stack (which subclasses LinearSeq) with a different error:
scala> val a = new scala.collection.immutable.Stack[Int]()a: scala.collection.immutable.Stack[Int] = Stack()
scala> a match { case head :: tail => println("headtail"); } <console>:7: error: constructor cannot be instantiated to expected type; found : collection.immutable.::[B] required: scala.collection.immutable.Stack[Int] a match { case head :: tail => println("headtail"); } ^
scala>
It would be nice indeed, but I'm sure there are all kinds of subtle reasons why it's better not to. :)
-0xe1a
Fri, 2011-06-17, 12:27
#9
Re: strange head :: tail pattern matching
Think he was talking to me :D
On Fri, Jun 17, 2011 at 2:04 AM, Alex Cruise wrote:
> Call me Alex please. :)
It says right there in the error!
scala.MatchError: WrappedArray(1) doesn't match head :: tail, nor does
it match nil. That's because both of those are list patterns, and a
list isn't an array.
Seq(1) happens to make a List, by happy co-incidence. If it made an
array you'd be out of luck.
You probably want to use this:
def foo(x: Int*) = x.toList match { case Nil => println("nil"); case
head :: tail => println("headtail"); }
which actually works!
On Thu, Jun 16, 2011 at 5:20 PM, john sullivan wrote:
> This result was unexpected for me. I get with both scala versions 2.8.1 and
> 2.9.0.1. Shouldn't I expect to match head :: tail in the first example? Why
> should x.toSeq fail to match, but x.toList match?
> Thanks, John
>
> scala> def foo(x: Int*) = x.toSeq match { case Nil => println("nil"); case
> head :: tail => println("headtail"); }
> foo: (x: Int*)Unit
>
> scala> foo(1)
>
> scala.MatchError: WrappedArray(1)
> at .foo(:8)
> at .(:10)
> at .()
> at RequestResult$.(:9)
> at RequestResult$.()
> at RequestResult$scala_repl_result()
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
> at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> at java.lang.reflect.Method.invoke(Method.java:597)
> at
> scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
> at
> scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
> at scala.util.control.Exception$Catch.apply(Exception.sca...
> scala> def foo(x: Int*) = x.toList match { case Nil => println("nil"); case
> head :: tail => println("headtail"); }
> foo: (x: Int*)Unit
>
> scala> foo(1)
>
> headtail
>
> scala> Seq(1) match { case Nil => println("nil"); case head :: tail =>
> println("headtail"); }
> headtail
>
> scala>
>
> --
> There are more things in heaven and earth, Horatio,
> Than are dreamt of in your philosophy.
>