how to implement "foldUntil"

173 views
Skip to first unread message

HamsterofDeath

unread,
Jan 1, 2013, 2:51:01 AM1/1/13
to scala...@googlegroups.com
hi community,

what is the functional version of:

var accumulated = ....
for (e <- coll) {if (accumulated.done) return accumulated else
accumulated.add(e)}

?

i cannot use takeWhile in advance, because i can only check the
stop-condition by looking at the already accumulated data.
in haskell, i would use scan & filter which would work because scan is
lazy - but in scala it would go over the complete collection first.

HamsterofDeath

unread,
Jan 1, 2013, 2:54:42 AM1/1/13
to scala...@googlegroups.com
(if there is a dirty functional version, that's fine as well as long as
the mutations are hidden)

Roland Kuhn

unread,
Jan 1, 2013, 7:24:22 AM1/1/13
to HamsterofDeath, scala...@googlegroups.com
Looks like tail recursion to me:

def rec(acc: Acc, it: Iterator[_]): Acc =
if (acc.done || !it.hasNext) acc
else rec(acc.added(it.next), it)
rec(new Acc, coll.iterator)
Dr. Roland Kuhn
Akka Tech Lead
Typesafe – The software stack for applications that scale.
twitter: @rolandkuhn

HamsterofDeath

unread,
Jan 1, 2013, 8:10:16 AM1/1/13
to scala...@googlegroups.com
yes, that's what i do now

Seth Tisue

unread,
Jan 1, 2013, 3:59:19 PM1/1/13
to scala...@googlegroups.com
On Tue, Jan 1, 2013 at 2:51 AM, HamsterofDeath <h-s...@gmx.de> wrote:
> i cannot use takeWhile in advance, because i can only check the
> stop-condition by looking at the already accumulated data.
> in haskell, i would use scan & filter which would work because scan is
> lazy - but in scala it would go over the complete collection first.

The Haskell solution is translatable into Scala using Stream or a view.

scala> Stream.from(1).scanLeft(0)(_ + _).takeWhile(_ < 100).last
res0: Int = 91

scala> List.range(1, 100).view.scanLeft(0)(_ + _).takeWhile(_ < 100).last
res1: Int = 91

Note that the view version fails in 2.9, but it does work in 2.10.

You might also think of using Iterator, since Iterator has scanLeft.
But it doesn't have `last`, so then you're stuck trying to get the
last item, and the only easy fix I can think of is `.toStream.last`.

--
Seth Tisue | Northwestern University | http://tisue.net
developer, NetLogo: http://ccl.northwestern.edu/netlogo/

Seth Tisue

unread,
Jan 4, 2013, 6:17:40 AM1/4/13
to scala...@googlegroups.com
On Tuesday, January 1, 2013 3:59:19 PM UTC-5, Seth Tisue wrote:
scala> List.range(1, 100).view.scanLeft(0)(_ + _).takeWhile(_ < 100).last
res1: Int = 91

Bob Hiestand points out that scanLeft on SeqView isn't actually lazy, though it seems to me that it should be. Sigh. I should have checked that before posting.

I've added a note about it to https://issues.scala-lang.org/browse/SI-4332
Reply all
Reply to author
Forward
0 new messages