This page is no longer maintained — Please continue to the home page at www.scala-lang.org

strange head :: tail pattern matching

9 replies
sullivan-
Joined: 2009-10-13,
User offline. Last seen 39 weeks 5 days ago.
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.
Alec Zorab
Joined: 2010-05-18,
User offline. Last seen 42 years 45 weeks ago.
Re: strange head :: tail pattern matching

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.
>

dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
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.
>>
>

Skavookie
Joined: 2011-02-20,
User offline. Last seen 1 year 24 weeks ago.
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.

Alex Cruise
Joined: 2008-12-17,
User offline. Last seen 2 years 26 weeks ago.
Re: Re: strange head :: tail pattern matching
On Thu, Jun 16, 2011 at 10:57 AM, Joshua Gooding <skavookie [at] gmail [dot] com> wrote:
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
Alex Cruise
Joined: 2008-12-17,
User offline. Last seen 2 years 26 weeks ago.
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> 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

sullivan-
Joined: 2009-10-13,
User offline. Last seen 39 weeks 5 days ago.
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:
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.
Derek Williams
Joined: 2009-06-13,
User offline. Last seen 42 years 45 weeks ago.
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.

Alex Cruise
Joined: 2008-12-17,
User offline. Last seen 2 years 26 weeks ago.
Re: strange head :: tail pattern matching
On Thu, Jun 16, 2011 at 5:41 PM, john sullivan <sullymandias [at] gmail [dot] com> wrote:
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
Alec Zorab
Joined: 2010-05-18,
User offline. Last seen 42 years 45 weeks ago.
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. :)

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland