|
View:
New views
10 Messages
—
Rating Filter:
Alert me
|
|
|
folding operators
by mscurtescu
::
Rate this Message:
Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message I am working my way through the Scala book and while trying to
understand exactly how the folding operators work (section 14.7) I don't see why the unit element is needed. As far as I can tell both folding operators could take only two arguments, the list and an operator. Instead of: (z /: List(a, b, c)) (op) = op(op(op(z, c), b), a) you would have something like: (op) /: List(a, b, c) = op(op(b, c), a) Can anyone give an example where the unit element is needed? Unless I am missing something obvious, maybe this should be clarified in the book. Thanks, Marius -- http://marius.scurtescu.com |
|
|
Re: folding operators
by Matt Hellige
::
Rate this Message:
Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message I can't comment on the treatment in the book, as I haven't looked at it yet.
In the most general case, the unit value is necessary because the types needn't all be the same. In other words, instead of an operator of type (A, A) => A for a List[A], we can use an operator of type (B, A) => B. In this case it's pretty clear why we must provide a "seed" value of type B to start things off... Here's an example: ("" /: List(1, 2, 3)) (_ + _) => "123" ("123" :\ List[Char]())(_ :: _) => List(1, 2, 3) However, you make a good observation! Indeed there is another operation which behaves as you describe. It can be used instead of fold in some cases (when the operation is of type (A, A) => A and has an obvious unit), and it is traditionally called "reduce". In fact it is defined in Scala as reduceLeft and reduceRight in trait Iterable. Comparing the types of fold and reduce is instructive: foldLeft [B](z : B)(op : (B, A) => B) : B reduceLeft [B >: A](op : (B, B) => B) : B Hope that helps... Matt On Jan 4, 2008 7:24 PM, Marius Scurtescu <marius.scurtescu@...> wrote: > I am working my way through the Scala book and while trying to > understand exactly how the folding operators work (section 14.7) I > don't see why the unit element is needed. > > As far as I can tell both folding operators could take only two > arguments, the list and an operator. > > Instead of: > (z /: List(a, b, c)) (op) = op(op(op(z, c), b), a) > you would have something like: > (op) /: List(a, b, c) = op(op(b, c), a) > > Can anyone give an example where the unit element is needed? > > Unless I am missing something obvious, maybe this should be clarified > in the book. > > Thanks, > Marius > > -- > http://marius.scurtescu.com > -- Matt Hellige / matt@... http://matt.immute.net |
|
|
Re: folding operators
by Erik Engbrecht
::
Rate this Message:
Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message scala> val xs = 1 :: 2 :: 3 :: 4 :: Nil
xs: List[Int] = List(1, 2, 3, 4)
scala> (0 /: xs) ((a: Int, b: Int) => a + b) res7: Int = 10 scala> (10 /: xs) ((a: Int, b: Int) => a + b)
res8: Int = 20
scala> How is it supposed to know what to start the fold with is there is no initial parameter? Also, notice that the z parameter doesn't need to be the same type of element as what is contained in the list. (I hope that's what you where asking)
On Jan 4, 2008 8:24 PM, Marius Scurtescu <marius.scurtescu@...> wrote: I am working my way through the Scala book and while trying to -- http://erikengbrecht.blogspot.com/ |
|
|
Re: folding operators
by mscurtescu
::
Rate this Message:
Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message Thanks for the clarifications, it all makes sense now.
From the book it wasn't clear that the types are not all the same, and reduce is not mentioned at all. Marius On 1/4/08, Matt Hellige <matt@...> wrote: > I can't comment on the treatment in the book, as I haven't looked at it yet. > > In the most general case, the unit value is necessary because the > types needn't all be the same. In other words, instead of an operator > of type (A, A) => A for a List[A], we can use an operator of type (B, > A) => B. In this case it's pretty clear why we must provide a "seed" > value of type B to start things off... Here's an example: > ("" /: List(1, 2, 3)) (_ + _) > => "123" > > ("123" :\ List[Char]())(_ :: _) > => List(1, 2, 3) > > However, you make a good observation! Indeed there is another > operation which behaves as you describe. It can be used instead of > fold in some cases (when the operation is of type (A, A) => A and has > an obvious unit), and it is traditionally called "reduce". In fact it > is defined in Scala as reduceLeft and reduceRight in trait Iterable. > Comparing the types of fold and reduce is instructive: > foldLeft [B](z : B)(op : (B, A) => B) : B > reduceLeft [B >: A](op : (B, B) => B) : B > > Hope that helps... > Matt > > On Jan 4, 2008 7:24 PM, Marius Scurtescu <marius.scurtescu@...> wrote: > > I am working my way through the Scala book and while trying to > > understand exactly how the folding operators work (section 14.7) I > > don't see why the unit element is needed. > > > > As far as I can tell both folding operators could take only two > > arguments, the list and an operator. > > > > Instead of: > > (z /: List(a, b, c)) (op) = op(op(op(z, c), b), a) > > you would have something like: > > (op) /: List(a, b, c) = op(op(b, c), a) > > > > Can anyone give an example where the unit element is needed? > > > > Unless I am missing something obvious, maybe this should be clarified > > in the book. > > > > Thanks, > > Marius > > > > -- > > http://marius.scurtescu.com > > > > > > -- > Matt Hellige / matt@... > http://matt.immute.net > -- http://marius.scurtescu.com |
|
|
Re: folding operators
by mscurtescu
::
Rate this Message:
Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message On 1/4/08, Erik Engbrecht <erik.engbrecht@...> wrote:
> scala> val xs = 1 :: 2 :: 3 :: 4 :: Nil > xs: List[Int] = List(1, 2, 3, 4) > > scala> (0 /: xs) ((a: Int, b: Int) => a + b) > res7: Int = 10 > > scala> (10 /: xs) ((a: Int, b: Int) => a + b) > res8: Int = 20 > > scala> > > How is it supposed to know what to start the fold with is there is no > initial parameter? If all the types are the same then just start with the last element of the list. > Also, notice that the z parameter doesn't need to be the same type of > element as what is contained in the list. Yes, that's what I was missing. Thanks, Marius -- http://marius.scurtescu.com |
|
|
Re: folding operators
by Geoff Reedy
::
Rate this Message:
Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message If you do not supply a starting value what should be returned when
folding an empty sequence? That is one use of the initial value. The other use is if the type of the result is different from the type of the elements in the sequence. Look at the type of the fold: Iterable[A]./:[B](z: B)(op: (B,A)=> B): B If an initial value were not required the 'op' would have to be of type (B,B)=>B. For example, it is possible to reverse a list using a fold: scala> ((Nil: List[Int]) /: List(1,2,3,4)){(xs, x) => x :: xs} res23: List[Int] = List(4, 3, 2, 1) It says to start with an empty list and prepend each element on to it. This would not be possible if both parameters to the operator had to be the same type. |
|
|
Re: folding operators
by Erik Engbrecht
::
Rate this Message:
Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message > How is it supposed to know what to start the fold with is there is no initial parameter? If all the types are the same then just start with the last element of the list. I believe that would be a reduce instead of a fold. Also, folds will succeed on empty lists: scala> (10 /: Nil) ((a: Int, b: Int) => a + b) res9: Int = 10 while reduces require at least one element: scala> val x1 = 1 :: Nil x1: List[Int] = List(1) scala> x1.reduceLeft((a: Int, b: Int) => a + b) res14: Int = 1 scala> Nil.reduceLeft((a: Int, b: Int) => a + b) java.lang.UnsupportedOperationException: Nil.reduceLeft
at scala.List.reduceLeft(List.scala:1005) at .<init>(<console>:5)
at .<clinit>(<console>) at RequestResult$.<init>(<console>:3)
at RequestResult$.<clinit>(<console>) at RequestResult$result(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethod... scala>
On Jan 4, 2008 9:01 PM, Marius Scurtescu <marius.scurtescu@...> wrote:
-- http://erikengbrecht.blogspot.com/ |
|
|
Re: folding operators
by tmorris
::
Rate this Message:
Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1 Marius Scurtescu wrote: > On 1/4/08, Erik Engbrecht <erik.engbrecht@...> wrote: >> scala> val xs = 1 :: 2 :: 3 :: 4 :: Nil >> xs: List[Int] = List(1, 2, 3, 4) >> >> scala> (0 /: xs) ((a: Int, b: Int) => a + b) >> res7: Int = 10 >> >> scala> (10 /: xs) ((a: Int, b: Int) => a + b) >> res8: Int = 20 >> >> scala> >> >> How is it supposed to know what to start the fold with is there is no >> initial parameter? > > If all the types are the same then just start with the last element of > the list. > > >> Also, notice that the z parameter doesn't need to be the same type of >> element as what is contained in the list. > > Yes, that's what I was missing. > > > Thanks, > Marius > > A helpful exercise might be to write reduce(Left/Right) in terms of fold(Left/Right). Notice that reduce is a partial function (undefined for empty lists). Also notice that trying to go the other way around is not possible. This should imply that reduce is a specialisation of fold. Therefore, to answer your question, fold is more general than reduce so you'd need fold for those more general cases. - -- Tony Morris http://tmorris.net/ Hey! We had 40,000 lines of C# here yesterday, but now there are 40 lines of... Dear God, what is a catamorphism?" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFHfuqumnpgrYe6r60RAj3EAKCtYGbuTFyLALSJlLsIgIpf4toKfwCgk2Sn qvh1D2Sj5WvcJJ7EBVc2Wcc= =zJmP -----END PGP SIGNATURE----- |
|
|
Re: folding operators
by Michael Campbell
::
Rate this Message:
Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message On Jan 4, 2008 8:50 PM, Erik Engbrecht <erik.engbrecht@...> wrote:
> scala> val xs = 1 :: 2 :: 3 :: 4 :: Nil > xs: List[Int] = List(1, 2, 3, 4) > > scala> (0 /: xs) ((a: Int, b: Int) => a + b) > res7: Int = 10 > > scala> (10 /: xs) ((a: Int, b: Int) => a + b) > res8: Int = 20 > > scala> > > How is it supposed to know what to start the fold with is there is no > initial parameter? Perhaps I'm being naive here, but perhaps ... the first element? (or last, depending on foldL or foldR) |
|
|
Re: folding operators
by Stanislas Klimoff-3
::
Rate this Message:
Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message Hi Marius,
On 1/5/08, Marius Scurtescu <marius.scurtescu@...> wrote: Can anyone give an example where the unit element is needed? I'm used to fold a list of strings into an empty StringBuilder (I'm not talking about Scala in particular in the moment).
HTH -- Best wishes, Stan Klimoff Grid Dynamics Consulting |
| Free embeddable forum powered by Nabble | Forum Help |