# Multiple blocks (unfold)

**URL:** <https://www.ruby-forum.com/t/multiple-blocks-unfold/53946>\
**Category:** Ruby\
**Created:** [December 17, 2005, 1:19am UTC](https://www.ruby-forum.com/t/multiple-blocks-unfold/53946 "2005-12-17T01:19:56Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [December 17, 2005, 1:19am UTC](https://www.ruby-forum.com/t/multiple-blocks-unfold/53946/1 "2005-12-17T01:19:56Z")

</div>

I’ve been pondering how to write an “unfold” in Ruby lately, and  
I’ve not really found any non-awkward ways to do it yet.

For those not familiar, unfold is basically the inverse of foldl  
(Ruby’s inject); in its native form (as seen in most functional  
languages), it takes four arguments:

- an initial state

- a predicate (tests the state to know when to stop)

- a transformer (converts a state to an output value)

- an incrementor (converts a state to the next state)

It would look something like:

def Array.unfold( s, p, f, g )  
arr = []  
until p.call( s )  
arr \<\< f.call( s )  
s = g.call( s )  
end  
arr  
end

You’d use it something like:

a = Array.unfold( 0, lambda { |s| s \> 10 }, lambda { |s| s \* 2 },  
lambda { |s| s + 1 } )

That’s pretty ugly in Ruby terms, though. The nicest way I’ve  
thought of so far would be something like:

class Unfolder  
def initialize &block  
(class \<\< self  
def self.stop? &block  
define\_method :stop?, &block  
end  
def self.f &block  
define\_method :f, &block  
end  
def self.g &block  
define\_method :g, &block  
end  
self  
end).class\_eval &block  
end

# reasonable defaults?

def stop?( s ) ; s ; end  
def f( s ) ; s ; end  
def g( s ) ; g.succ ; end  
end

def Array.unfold( s, &block )  
unfolder = Unfolder.new &block  
arr = []  
until unfolder.stop? s  
arr \<\< unfolder.f s  
s = unfolder.g s  
end  
arr  
end

Which could be used something like:

a = Array.unfold( 0 ) {  
stop? { |s| s \> 10 }  
f { |s| s \* 2 }  
g { |s| s + 1 }  
}

But that’s kinda icky and probably slow-like.

Anyone got some better ideas?

-mental

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [December 17, 2005, 1:22am UTC](https://www.ruby-forum.com/t/multiple-blocks-unfold/53946/2 "2005-12-17T01:22:58Z")

</div>

Sorry, needs some parens to parse:

Quoting removed\_email\_address@domain.invalid:

> def Array.unfold( s, &block )  
> unfolder = Unfolder.new &block  
> arr = []  
> until unfolder.stop? s  
> arr \<\< unfolder.f( s )  
> s = unfolder.g( s )  
> end  
> arr  
> end

-mental

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [December 17, 2005, 1:56am UTC](https://www.ruby-forum.com/t/multiple-blocks-unfold/53946/3 "2005-12-17T01:56:03Z")

</div>

removed\_email\_address@domain.invalid wrote:

> Anyone got some better ideas?

The only other idea I can think of at the moment is one I’ve seen in a  
lot of Java DSLs (and in FlexMock):

class Unfolder  
class \<\< self  
def stop? &block  
new.stop? &block  
end  
def f &block  
new.f &block  
end  
def g &block  
new.g &block  
end  
end

# reasonable defaults?

def initialize  
@p = lambda {|s| !s}  
@f = lambda {|s| s}  
@g = lambda {|s| s.succ}  
end

def stop?(&b) @p = b; self end  
def f(&b) @f = b; self end  
def g(&b) @g = b; self end  
def unfold(s)  
arr = []  
until @p.call(s)  
arr \<\< @f.call(s)  
s = @g.call(s)  
end  
arr  
end  
end

Usage:

a = Unfolder.stop? { |s| s \> 10 }.f { |s| s \* 2 }.g { |s| s + 1  
}.unfold(0)

Completely untested, and full of duplication, but you get the idea.

Devin

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [December 17, 2005, 2:05am UTC](https://www.ruby-forum.com/t/multiple-blocks-unfold/53946/4 "2005-12-17T02:05:05Z")

</div>

Quoting Devin M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> Usage:
> 
> a = Unfolder.stop? { |s| s \> 10 }.f { |s| s \* 2 }.g { |s| s + 1  
> }.unfold(0)

Hey, that’s not too bad. Use the named parameter idiom from Java.

It’s a little weird from a Ruby perspective, but except for being  
(essentially) curried it’s rather like the way you’d do it in  
Smalltalk.

-mental

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [December 17, 2005, 4:45pm UTC](https://www.ruby-forum.com/t/multiple-blocks-unfold/53946/5 "2005-12-17T16:45:32Z")

</div>

removed\_email\_address@domain.invalid writes:

> I’ve been pondering how to write an “unfold” in Ruby lately, and  
> I’ve not really found any non-awkward ways to do it yet.

C’mon, let’s do complete hylomorphisms. 🙂

class Hylo  
class \<\< self  
alias\_method :taking, :new  
end

def initialize(start)  
@start = start

```
# Useful defaults.
@final = lambda { |x| x.nil? }
@map = lambda { |x| x }

@init = []
@each = lambda { |a, e| a << e }

@step = lambda { |x| raise ArgumentError, "No do block given." }

```

end

def do(&block); @step = block; self; end  
def till(&block); @final = block; self; end  
def collecting(&block); @map = block; self; end  
def injecting(init, &block); @init, @each = init, (block||@each);  
self; end

def to\_a  
v = @start  
r = @init

```
until @final[v]
  r = @each[r, @map[v]]
  v = @step[v]
end

r

```

end  
end

def evens(n)  
Hylo.new(0).  
do { |x| x + 2 }.  
till { |x| x \>= n }.  
to\_a  
end

def fact(n)  
Hylo.taking(n).  
do { |x| x - 1 }.  
till { |x| x \<= 1 }.  
injecting(1) { |a, e| a \* e }.to\_a  
end

def tobin(n)  
Hylo.new(n).  
do { |x| x / 2 }.  
till { |x| x \<= 0 }.  
collecting { |x| (x % 2).to\_s }.  
injecting(’’).to\_a  
end

def expand(n)  
Hylo.new(n).  
do { |x| x[1…-1] }.  
till { |x| x.empty? }.  
collecting { |x| x.first[0] \* x.first[1] }.  
injecting(’’).to\_a  
end

p evens(20)  
p fact(7)  
p tobin(42)  
p expand([[‘a’, 6], [‘b’, 4], [‘c’, 2]])

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [December 17, 2005, 8:34pm UTC](https://www.ruby-forum.com/t/multiple-blocks-unfold/53946/6 "2005-12-17T20:34:14Z")

</div>

On Sun, 2005-12-18 at 00:41 +0900, Christian N. wrote:

> removed\_email\_address@domain.invalid writes:
> 
> > I’ve been pondering how to write an “unfold” in Ruby lately, and  
> > I’ve not really found any non-awkward ways to do it yet.
> 
> C’mon, let’s do complete hylomorphisms. 🙂

Hey, this is pretty good. It might be worth into turning into a gem.

Only thing is I don’t know about to\_a … there’s no real reason the  
result has to be an array versus some other type (I’ve got lazy streams  
in mind, at least).

-mental

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [December 17, 2005, 9:26pm UTC](https://www.ruby-forum.com/t/multiple-blocks-unfold/53946/7 "2005-12-17T21:26:03Z")

</div>

On Sat, Dec 17, 2005 at 10:03:32AM +0900, removed\_email\_address@domain.invalid wrote:

> It’s a little weird from a Ruby perspective, but except for being  
> (essentially) curried it’s rather like the way you’d do it in  
> Smalltalk.

I wrote up a small metaprogramming library back in the spring which  
adds this syntax to Ruby classes/modules in an (IMHO) convenient way:

[http://creo.hu/~csaba/ruby/multiblocks/](http://creo.hu/~csaba/ruby/multiblocks/)

Csaba

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [December 18, 2005, 3:24pm UTC](https://www.ruby-forum.com/t/multiple-blocks-unfold/53946/8 "2005-12-18T15:24:52Z")

</div>

MenTaLguY [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

> Only thing is I don’t know about to\_a … there’s no real reason the  
> result has to be an array versus some other type (I’ve got lazy streams  
> in mind, at least).

True, #to\_a is left-over. Not sure what it should be called, tho.

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [December 17, 2005, 11:34pm UTC](https://www.ruby-forum.com/t/multiple-blocks-unfold/53946/9 "2005-12-17T23:34:30Z")

</div>

In article [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid),  
Christian N. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> removed\_email\_address@domain.invalid writes:
> 
> > I’ve been pondering how to write an “unfold” in Ruby lately, and  
> > I’ve not really found any non-awkward ways to do it yet.
> 
> C’mon, let’s do complete hylomorphisms. 🙂

Had to look that one up. wikipedia says:  
a philosophical concept that highlights the significance of matter in  
the  
composition of being, regarding matter to be as essential to a being as  
its  
form.

…but I don’t feel any more enightened than I was prior to looking it  
up.  
What does ‘hylomophism’ mean in this context? Most all of the google  
hits had  
something to do with philosophy.

> # Useful defaults.
> 
> def till(&block); @final = block; self; end  
> end  
> to\_a  
> Hylo.new(n).  
> collecting { |x| x.first[0] \* x.first[1] }.  
> injecting(‘’).to\_a  
> end
> 
> p evens(20)  
> p fact(7)  
> p tobin(42)  
> p expand([[‘a’, 6], [‘b’, 4], [‘c’, 2]])

this is quite cool even if I’m not quite sure how hylomorphism applys.

BTW: in regards to the other ‘advanced Ruby book’ threads recently, this  
is  
just the sort of thing I’d like to see in a ‘Higher Order Ruby’ type  
book.

Phil
