- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Why does Scala want a String?
Mon, 2011-04-18, 14:19
I'm doing a Travelling Salesman problem--find the total distance to
visit a set of cities,
visiting each city only once and returning to the starting point.
That's easy enough to
do with a variable and a loop. But I'd like to hide the variable
behind a higher-order
function, like so:
pairwiseFold(v, seq)(f) = f(seq(0), seq(1)) + f(seq(1), seq(2))
+ ... + f(seq.last, seq(0))
My attempt looks like
def pairwiseFold[T](seq: Seq[T], startValue: T)(f: (T, T) => Number)
= {
var result: Number = f(startValue, seq(0))
var prev: T = startValue
seq foreach(v => { result += f(prev, v); prev = v })
result
}
However, Scala complains about the f(prev, v):
type mismatch; found : java.lang.Number required: String
Not surprisingly, if I change this to (f(prev, v) toString), Scala
complains that it
requires a Number.
Is this a Scala bug? If not, can someone explain what's going on?
Thanks,
Dave Matuszek
Mon, 2011-04-18, 14:47
#2
Re: Why does Scala want a String?
you often get advise that a string is needed in scala, because that's the fall back when a type doesn't understand + (String unfortunately has + for catenation).
thing here is that java.lang.Number doesn't have a + method !
what you want is probably scala.math.Numeric. that still doesn't have '+' but instead 'plus'....
def pairwiseFold[T, N : Numeric](seq: Seq[T], startValue: T)(f: (T, T) => N) = {
val n = implicitly[ Numeric[ N ]]
var result: N = f(startValue, seq(0))
var prev: T = startValue
seq foreach(v => { result = n.plus( result, f(prev, v)); prev = v })
result
}
by the way, the initialization of the fold is wrong, IMO:
val res0 = pairwiseFold( List( "2", "3", "4" ), "1" ) { (a, b) => (a(0)-48) * (b(0)-48) }
assert( (1*2 + 2*3 + 3*4) == res0 ) // ouch, 1*2 is added twice!
a correct and more concise version would be:
def pairwiseFold[T, N : Numeric](seq: Seq[T])(f: (T, T) => N) = {
val n = implicitly[ Numeric[ N ]]
seq.sliding( 2, 1 ).map( pair => f( pair( 0 ), pair( 1 ))).reduceLeft( n.plus( _, _ ))
}
val res1 = pairwiseFold( List( "1", "2", "3", "4" )) { (a, b) => (a(0)-48) * (b(0)-48) }
assert( (1*2 + 2*3 + 3*4) == res1 ) // ok!
best, -sciss-
On 18 Apr 2011, at 14:19, david.matuszek wrote:
> I'm doing a Travelling Salesman problem--find the total distance to
> visit a set of cities,
> visiting each city only once and returning to the starting point.
> That's easy enough to
> do with a variable and a loop. But I'd like to hide the variable
> behind a higher-order
> function, like so:
>
> pairwiseFold(v, seq)(f) = f(seq(0), seq(1)) + f(seq(1), seq(2))
> + ... + f(seq.last, seq(0))
>
> My attempt looks like
>
> def pairwiseFold[T](seq: Seq[T], startValue: T)(f: (T, T) => Number)
> = {
> var result: Number = f(startValue, seq(0))
> var prev: T = startValue
> seq foreach(v => { result += f(prev, v); prev = v })
> result
> }
>
> However, Scala complains about the f(prev, v):
> type mismatch; found : java.lang.Number required: String
> Not surprisingly, if I change this to (f(prev, v) toString), Scala
> complains that it
> requires a Number.
>
> Is this a Scala bug? If not, can someone explain what's going on?
>
> Thanks,
> Dave Matuszek
Mon, 2011-04-18, 15:07
#3
Re: Why does Scala want a String?
Thanks for the wonderful (and quick!) replies. I'm guessing Number
can't have a + method because it doesn't know how to implement it for
an unspecified numeric type? Anyway, both replies answer my question
perfectly. I'm finding Sciss's version a bit harder to read (I _am_ a
Scala newbie, after all), but still understandable; and thanks for
bringing in implicits! I knew I should use an implicit here, but
didn't know how, so this is even more help than I had asked for.
--Dave
On Apr 18, 9:35 am, Sciss wrote:
> you often get advise that a string is needed in scala, because that's the fall back when a type doesn't understand + (String unfortunately has + for catenation).
>
> thing here is that java.lang.Number doesn't have a + method !
>
> what you want is probably scala.math.Numeric. that still doesn't have '+' but instead 'plus'....
>
> def pairwiseFold[T, N : Numeric](seq: Seq[T], startValue: T)(f: (T, T) => N) = {
> val n = implicitly[ Numeric[ N ]]
> var result: N = f(startValue, seq(0))
> var prev: T = startValue
> seq foreach(v => { result = n.plus( result, f(prev, v)); prev = v })
> result
>
> }
>
> by the way, the initialization of the fold is wrong, IMO:
>
> val res0 = pairwiseFold( List( "2", "3", "4" ), "1" ) { (a, b) => (a(0)-48) * (b(0)-48) }
> assert( (1*2 + 2*3 + 3*4) == res0 ) // ouch, 1*2 is added twice!
>
> a correct and more concise version would be:
>
> def pairwiseFold[T, N : Numeric](seq: Seq[T])(f: (T, T) => N) = {
> val n = implicitly[ Numeric[ N ]]
> seq.sliding( 2, 1 ).map( pair => f( pair( 0 ), pair( 1 ))).reduceLeft( n.plus( _, _ ))
>
> }
>
> val res1 = pairwiseFold( List( "1", "2", "3", "4" )) { (a, b) => (a(0)-48) * (b(0)-48) }
> assert( (1*2 + 2*3 + 3*4) == res1 ) // ok!
>
> best, -sciss-
>
> On 18 Apr 2011, at 14:19, david.matuszek wrote:
>
> > I'm doing a Travelling Salesman problem--find the total distance to
> > visit a set of cities,
> > visiting each city only once and returning to the starting point.
> > That's easy enough to
> > do with a variable and a loop. But I'd like to hide the variable
> > behind a higher-order
> > function, like so:
>
> > pairwiseFold(v, seq)(f) = f(seq(0), seq(1)) + f(seq(1), seq(2))
> > + ... + f(seq.last, seq(0))
>
> > My attempt looks like
>
> > def pairwiseFold[T](seq: Seq[T], startValue: T)(f: (T, T) => Number)
> > = {
> > var result: Number = f(startValue, seq(0))
> > var prev: T = startValue
> > seq foreach(v => { result += f(prev, v); prev = v })
> > result
> > }
>
> > However, Scala complains about the f(prev, v):
> > type mismatch; found : java.lang.Number required: String
> > Not surprisingly, if I change this to (f(prev, v) toString), Scala
> > complains that it
> > requires a Number.
>
> > Is this a Scala bug? If not, can someone explain what's going on?
>
> > Thanks,
> > Dave Matuszek
Mon, 2011-04-18, 15:17
#4
Re: Re: Why does Scala want a String?
For even more kicks, here's the oneliner:
def pairwiseFold[T, N : Numeric](seq: Seq[T])(f: (T, T) => N) =
seq.sliding( 2, 1 ) map { case Seq(a,b) => f(a,b) } reduceLeft implicitly[ Numeric[ N ]].plus
On Mon, Apr 18, 2011 at 3:57 PM, david.matuszek <david.matuszek@gmail.com> wrote:
--
Viktor Klang,
Director of Research and Development
Scalable Solutions
Code: github.com/viktorklang
Follow: twitter.com/viktorklang
Read: klangism.tumblr.com
def pairwiseFold[T, N : Numeric](seq: Seq[T])(f: (T, T) => N) =
seq.sliding( 2, 1 ) map { case Seq(a,b) => f(a,b) } reduceLeft implicitly[ Numeric[ N ]].plus
On Mon, Apr 18, 2011 at 3:57 PM, david.matuszek <david.matuszek@gmail.com> wrote:
Thanks for the wonderful (and quick!) replies. I'm guessing Number
can't have a + method because it doesn't know how to implement it for
an unspecified numeric type? Anyway, both replies answer my question
perfectly. I'm finding Sciss's version a bit harder to read (I _am_ a
Scala newbie, after all), but still understandable; and thanks for
bringing in implicits! I knew I should use an implicit here, but
didn't know how, so this is even more help than I had asked for.
--Dave
On Apr 18, 9:35 am, Sciss <cont...@sciss.de> wrote:
> you often get advise that a string is needed in scala, because that's the fall back when a type doesn't understand + (String unfortunately has + for catenation).
>
> thing here is that java.lang.Number doesn't have a + method !
>
> what you want is probably scala.math.Numeric. that still doesn't have '+' but instead 'plus'....
>
> def pairwiseFold[T, N : Numeric](seq: Seq[T], startValue: T)(f: (T, T) => N) = {
> val n = implicitly[ Numeric[ N ]]
> var result: N = f(startValue, seq(0))
> var prev: T = startValue
> seq foreach(v => { result = n.plus( result, f(prev, v)); prev = v })
> result
>
> }
>
> by the way, the initialization of the fold is wrong, IMO:
>
> val res0 = pairwiseFold( List( "2", "3", "4" ), "1" ) { (a, b) => (a(0)-48) * (b(0)-48) }
> assert( (1*2 + 2*3 + 3*4) == res0 ) // ouch, 1*2 is added twice!
>
> a correct and more concise version would be:
>
> def pairwiseFold[T, N : Numeric](seq: Seq[T])(f: (T, T) => N) = {
> val n = implicitly[ Numeric[ N ]]
> seq.sliding( 2, 1 ).map( pair => f( pair( 0 ), pair( 1 ))).reduceLeft( n.plus( _, _ ))
>
> }
>
> val res1 = pairwiseFold( List( "1", "2", "3", "4" )) { (a, b) => (a(0)-48) * (b(0)-48) }
> assert( (1*2 + 2*3 + 3*4) == res1 ) // ok!
>
> best, -sciss-
>
> On 18 Apr 2011, at 14:19, david.matuszek wrote:
>
> > I'm doing a Travelling Salesman problem--find the total distance to
> > visit a set of cities,
> > visiting each city only once and returning to the starting point.
> > That's easy enough to
> > do with a variable and a loop. But I'd like to hide the variable
> > behind a higher-order
> > function, like so:
>
> > pairwiseFold(v, seq)(f) = f(seq(0), seq(1)) + f(seq(1), seq(2))
> > + ... + f(seq.last, seq(0))
>
> > My attempt looks like
>
> > def pairwiseFold[T](seq: Seq[T], startValue: T)(f: (T, T) => Number)
> > = {
> > var result: Number = f(startValue, seq(0))
> > var prev: T = startValue
> > seq foreach(v => { result += f(prev, v); prev = v })
> > result
> > }
>
> > However, Scala complains about the f(prev, v):
> > type mismatch; found : java.lang.Number required: String
> > Not surprisingly, if I change this to (f(prev, v) toString), Scala
> > complains that it
> > requires a Number.
>
> > Is this a Scala bug? If not, can someone explain what's going on?
>
> > Thanks,
> > Dave Matuszek
--
Viktor Klang,
Director of Research and Development
Scalable Solutions
Code: github.com/viktorklang
Follow: twitter.com/viktorklang
Read: klangism.tumblr.com
Mon, 2011-04-18, 15:27
#5
Re: Re: Why does Scala want a String?
i should have maybe explained what `N : Numeric` does, but i thought this could be easily found on the web.
to my surprise there is no really good overview of it, you can only puzzle it together from various sources, e.g.
http://stackoverflow.com/questions/4033021/scala-implicit-conversion-of-...
http://www.scala-lang.org/node/6021
http://stackoverflow.com/questions/2982276/what-is-a-context-bound-in-scala
it is a shorthand writing for
def pairwiseFold[T, N ](seq: Seq[T])(f: (T, T) => N)( implicit n: Numeric[ N ])
which means that you can pass in any type `N` for which an implicit value `Numeric[ N ]` exists, this is called context bound.
essentially, the arithmetic operations are not part of the type `N` itself, but we now know there is a value (`n`) which can perform
them, like `n.plus( a, b )`, `n.times( a, b )` etc.
best, -sciss-
On 18 Apr 2011, at 14:57, david.matuszek wrote:
> Thanks for the wonderful (and quick!) replies. I'm guessing Number
> can't have a + method because it doesn't know how to implement it for
> an unspecified numeric type? Anyway, both replies answer my question
> perfectly. I'm finding Sciss's version a bit harder to read (I _am_ a
> Scala newbie, after all), but still understandable; and thanks for
> bringing in implicits! I knew I should use an implicit here, but
> didn't know how, so this is even more help than I had asked for.
>
> --Dave
>
> On Apr 18, 9:35 am, Sciss wrote:
>> you often get advise that a string is needed in scala, because that's the fall back when a type doesn't understand + (String unfortunately has + for catenation).
>>
>> thing here is that java.lang.Number doesn't have a + method !
>>
>> what you want is probably scala.math.Numeric. that still doesn't have '+' but instead 'plus'....
>>
>> def pairwiseFold[T, N : Numeric](seq: Seq[T], startValue: T)(f: (T, T) => N) = {
>> val n = implicitly[ Numeric[ N ]]
>> var result: N = f(startValue, seq(0))
>> var prev: T = startValue
>> seq foreach(v => { result = n.plus( result, f(prev, v)); prev = v })
>> result
>>
>> }
>>
>> by the way, the initialization of the fold is wrong, IMO:
>>
>> val res0 = pairwiseFold( List( "2", "3", "4" ), "1" ) { (a, b) => (a(0)-48) * (b(0)-48) }
>> assert( (1*2 + 2*3 + 3*4) == res0 ) // ouch, 1*2 is added twice!
>>
>> a correct and more concise version would be:
>>
>> def pairwiseFold[T, N : Numeric](seq: Seq[T])(f: (T, T) => N) = {
>> val n = implicitly[ Numeric[ N ]]
>> seq.sliding( 2, 1 ).map( pair => f( pair( 0 ), pair( 1 ))).reduceLeft( n.plus( _, _ ))
>>
>> }
>>
>> val res1 = pairwiseFold( List( "1", "2", "3", "4" )) { (a, b) => (a(0)-48) * (b(0)-48) }
>> assert( (1*2 + 2*3 + 3*4) == res1 ) // ok!
>>
>> best, -sciss-
>>
>> On 18 Apr 2011, at 14:19, david.matuszek wrote:
>>
>>> I'm doing a Travelling Salesman problem--find the total distance to
>>> visit a set of cities,
>>> visiting each city only once and returning to the starting point.
>>> That's easy enough to
>>> do with a variable and a loop. But I'd like to hide the variable
>>> behind a higher-order
>>> function, like so:
>>
>>> pairwiseFold(v, seq)(f) = f(seq(0), seq(1)) + f(seq(1), seq(2))
>>> + ... + f(seq.last, seq(0))
>>
>>> My attempt looks like
>>
>>> def pairwiseFold[T](seq: Seq[T], startValue: T)(f: (T, T) => Number)
>>> = {
>>> var result: Number = f(startValue, seq(0))
>>> var prev: T = startValue
>>> seq foreach(v => { result += f(prev, v); prev = v })
>>> result
>>> }
>>
>>> However, Scala complains about the f(prev, v):
>>> type mismatch; found : java.lang.Number required: String
>>> Not surprisingly, if I change this to (f(prev, v) toString), Scala
>>> complains that it
>>> requires a Number.
>>
>>> Is this a Scala bug? If not, can someone explain what's going on?
>>
>>> Thanks,
>>> Dave Matuszek
Mon, 2011-04-18, 15:37
#6
Re: Why does Scala want a String?
java.lang.Number does not have a "+" method. scala converts the number into a string to make "+" work, similar to
System.out.println(obj+" another string ") where toString is called on obj.
change Number to Double and it should work.
-------- Original-Nachricht --------
> Datum: Mon, 18 Apr 2011 06:19:05 -0700 (PDT)
> Von: "david.matuszek"
> An: scala-user
> Betreff: [scala-user] Why does Scala want a String?
> I'm doing a Travelling Salesman problem--find the total distance to
> visit a set of cities,
> visiting each city only once and returning to the starting point.
> That's easy enough to
> do with a variable and a loop. But I'd like to hide the variable
> behind a higher-order
> function, like so:
>
> pairwiseFold(v, seq)(f) = f(seq(0), seq(1)) + f(seq(1), seq(2))
> + ... + f(seq.last, seq(0))
>
> My attempt looks like
>
> def pairwiseFold[T](seq: Seq[T], startValue: T)(f: (T, T) => Number)
> = {
> var result: Number = f(startValue, seq(0))
> var prev: T = startValue
> seq foreach(v => { result += f(prev, v); prev = v })
> result
> }
>
> However, Scala complains about the f(prev, v):
> type mismatch; found : java.lang.Number required: String
> Not surprisingly, if I change this to (f(prev, v) toString), Scala
> complains that it
> requires a Number.
>
> Is this a Scala bug? If not, can someone explain what's going on?
>
> Thanks,
> Dave Matuszek
Mon, 2011-04-18, 15:47
#7
Re: Re: Why does Scala want a String?
You can pull a "+" method into scope by importing from the implicit, eg:
def pairwiseFold[T, N : Numeric](seq: Seq[T])(f: (T, T) => N) = {
val n = implicitly[ Numeric[ N ]]
import n._
seq.sliding( 2, 1 ).map( pair => f( pair( 0 ), pair( 1
))).reduceLeft( _ + _ )
}
(done from memory, untested)
On Mon, Apr 18, 2011 at 3:14 PM, Sciss wrote:
> i should have maybe explained what `N : Numeric` does, but i thought this could be easily found on the web.
>
> to my surprise there is no really good overview of it, you can only puzzle it together from various sources, e.g.
>
> http://stackoverflow.com/questions/4033021/scala-implicit-conversion-of-int-to-numericint
> http://www.scala-lang.org/node/6021
> http://stackoverflow.com/questions/2982276/what-is-a-context-bound-in-scala
>
> it is a shorthand writing for
>
> def pairwiseFold[T, N ](seq: Seq[T])(f: (T, T) => N)( implicit n: Numeric[ N ])
>
> which means that you can pass in any type `N` for which an implicit value `Numeric[ N ]` exists, this is called context bound.
>
> essentially, the arithmetic operations are not part of the type `N` itself, but we now know there is a value (`n`) which can perform
> them, like `n.plus( a, b )`, `n.times( a, b )` etc.
>
> best, -sciss-
>
>
>
>
> On 18 Apr 2011, at 14:57, david.matuszek wrote:
>
>> Thanks for the wonderful (and quick!) replies. I'm guessing Number
>> can't have a + method because it doesn't know how to implement it for
>> an unspecified numeric type? Anyway, both replies answer my question
>> perfectly. I'm finding Sciss's version a bit harder to read (I _am_ a
>> Scala newbie, after all), but still understandable; and thanks for
>> bringing in implicits! I knew I should use an implicit here, but
>> didn't know how, so this is even more help than I had asked for.
>>
>> --Dave
>>
>> On Apr 18, 9:35 am, Sciss wrote:
>>> you often get advise that a string is needed in scala, because that's the fall back when a type doesn't understand + (String unfortunately has + for catenation).
>>>
>>> thing here is that java.lang.Number doesn't have a + method !
>>>
>>> what you want is probably scala.math.Numeric. that still doesn't have '+' but instead 'plus'....
>>>
>>> def pairwiseFold[T, N : Numeric](seq: Seq[T], startValue: T)(f: (T, T) => N) = {
>>> val n = implicitly[ Numeric[ N ]]
>>> var result: N = f(startValue, seq(0))
>>> var prev: T = startValue
>>> seq foreach(v => { result = n.plus( result, f(prev, v)); prev = v })
>>> result
>>>
>>> }
>>>
>>> by the way, the initialization of the fold is wrong, IMO:
>>>
>>> val res0 = pairwiseFold( List( "2", "3", "4" ), "1" ) { (a, b) => (a(0)-48) * (b(0)-48) }
>>> assert( (1*2 + 2*3 + 3*4) == res0 ) // ouch, 1*2 is added twice!
>>>
>>> a correct and more concise version would be:
>>>
>>> def pairwiseFold[T, N : Numeric](seq: Seq[T])(f: (T, T) => N) = {
>>> val n = implicitly[ Numeric[ N ]]
>>> seq.sliding( 2, 1 ).map( pair => f( pair( 0 ), pair( 1 ))).reduceLeft( n.plus( _, _ ))
>>>
>>> }
>>>
>>> val res1 = pairwiseFold( List( "1", "2", "3", "4" )) { (a, b) => (a(0)-48) * (b(0)-48) }
>>> assert( (1*2 + 2*3 + 3*4) == res1 ) // ok!
>>>
>>> best, -sciss-
>>>
>>> On 18 Apr 2011, at 14:19, david.matuszek wrote:
>>>
>>>> I'm doing a Travelling Salesman problem--find the total distance to
>>>> visit a set of cities,
>>>> visiting each city only once and returning to the starting point.
>>>> That's easy enough to
>>>> do with a variable and a loop. But I'd like to hide the variable
>>>> behind a higher-order
>>>> function, like so:
>>>
>>>> pairwiseFold(v, seq)(f) = f(seq(0), seq(1)) + f(seq(1), seq(2))
>>>> + ... + f(seq.last, seq(0))
>>>
>>>> My attempt looks like
>>>
>>>> def pairwiseFold[T](seq: Seq[T], startValue: T)(f: (T, T) => Number)
>>>> = {
>>>> var result: Number = f(startValue, seq(0))
>>>> var prev: T = startValue
>>>> seq foreach(v => { result += f(prev, v); prev = v })
>>>> result
>>>> }
>>>
>>>> However, Scala complains about the f(prev, v):
>>>> type mismatch; found : java.lang.Number required: String
>>>> Not surprisingly, if I change this to (f(prev, v) toString), Scala
>>>> complains that it
>>>> requires a Number.
>>>
>>>> Is this a Scala bug? If not, can someone explain what's going on?
>>>
>>>> Thanks,
>>>> Dave Matuszek
>
>
Greetings,
> def pairwiseFold[T](seq: Seq[T], startValue: T)(f: (T, T) => Number)
> = {
> var result: Number = f(startValue, seq(0))
> var prev: T = startValue
> seq foreach(v => { result += f(prev, v); prev = v })
> result
> }
>
The issue here is that Number is java.lang.Number, which doesn't have
a Scala Rich wrapper class to provide += implementation. The compiler
interprets the += to be a String concatination.
Changing `Number` to `Double` or `Int` (or a more appropriate type)
solves the problem.
- Mahmood