Functional Code Examples in Ruby

Ruby's yield feature in relation to computer science

Ruby's yield is not an iterator like in C# and Python. yield itself is actually a really simple concept once you understand how blocks work in Ruby.

Yes, blocks are a functional programming feature, even though Ruby is not properly a functional language. In fact, Ruby uses the method lambda to create block objects, which is borrowed from Lisp's syntax for creating anonymous functions — which is what blocks are. From a computer science standpoint, Ruby's blocks (and Lisp's lambda functions) are closures. In Ruby, methods usually take only one block. (You can pass more, but it's awkward.)

The yield keyword in Ruby is just a way of calling a block that's been given to a method. These two examples are equivalent:

def with_log
output = yield # We're calling our block here with yield
puts "Returned value is #{output}"
end

def with_log(&stuff_to_do) # the & tells Ruby to convert into
# an object without calling lambda
output = stuff_to_do.call # We're explicitly calling the block here
puts "Returned value is #{output}"
end

In the first case, we're just assuming there's a block and say to call it. In the other, Ruby wraps the block in an object and passes it as an argument. The first is more efficient and readable, but they're effectively the same. You'd call either one like this:

with_log do
a = 5
other_num = gets.to_i
@my_var = a + other_num
end

And it would print the value that wound up getting assigned to @my_var. (OK, so that's a completely stupid function, but I think you get the idea.)

Blocks are used for a lot of things in Ruby. Almost every place you'd use a loop in a language like Java, it's replaced in Ruby with methods that take blocks. For example,

[1,2,3].each {|value| print value} # prints "123"
[1,2,3].map {|value| 2**value} # returns [2, 4, 8]
[1,2,3].reject {|value| value % 2 == 0} # returns [1, 3]

As Andrew noted, it's also commonly used for opening files and many other places. Basically anytime you have a standard function that could use some custom logic (like sorting an array or processing a file), you'll use a block. There are other uses too, but this answer is already so long I'm afraid it will cause heart attacks in readers with weaker constitutions. Hopefully this clears up the confusion on this topic.

Imperative vs Functional Programming in Ruby

You're not wrong. It is often the case that a purely functional solution will be slower than a destructive one. Immutable values generally mean a lot more allocation has to go on unless the language is very well optimized for them (which Ruby isn't).

However, it doesn't often matter. Worrying about the performance of specific operations is not a great use of your time 99% of the time. Shaving off a microsecond from a piece of code that runs 100 times a second is simply not a win.

The best approach is usually to do whatever makes your code cleanest. Very often this means taking advantage of the functional features of the language — for example, map and select instead of map! and keep_if. Then, if you need to speed things up, you have a nice, clean codebase that you can make changes to without fear that your changes will make one piece of code stomp over another piece's data.

ruby functional : best practice?

You should avoid adding to Integer unless you feel the method is truly addressing a behaviour of all Integers. Even then you should beware collisions.

Other than that, there is no inherent reason to choose either the second or third forms over the other, especially in your simple example.

Code blocks and methods offer different approaches to code re-use. Blocks work nicely when the "outside" pattern is repeated, and you just want to vary a few lines inside. Methods work nicely when you need to do the exact same "inner" logic in multiple places.

If your filtering logic is indeed repeated in multiple places, then I would favour making it a method on a mixin, or a class method of a suitable custom class, and calling that method in the block. Which is your second example. Otherwise, the direct one-liner with block is suitable for purpose and I can read it all in place, which offers a slight readability advantage (provided code stays DRY) - which is your third example.

create a ruby enumerable from a first element, and a function to get the next element from the previous one

What you are asking about is called an unfold (which is called Stream.iterate in scala), or more generically, an anamorphism. It is the exact category-theoretical dual of a fold (which is called Enumerable#inject in ruby) aka a catamorphism.

Is there something like this already ?

Unfortunately, there is no method in the core or standard library which performs this function.

But is it idiomatic ?

I would probably make it a singleton method of Enumerator and use Kernel#loop instead of while true, but that's about it. Otherwise, yes, your code is pretty idiomatic.

And while we're at it, let's call it unfold:

def Enumerator.unfold(start)
new do |y|
loop do
y << start
start = yield start
end
end
end

Is Ruby a functional language?

I most definitely think you can use functional style in Ruby.

One of the most critical aspects to be able to program in a functional style is if the language supports higher order functions... which Ruby does.

That said, it's easy to program in Ruby in a non-functional style as well. Another key aspect of functional style is to not have state, and have real mathematical functions that always return the same value for a given set of inputs. This can be done in Ruby, but it is not enforced in the language like something more strictly functional like Haskell.

So, yeah, it supports functional style, but it also will let you program in a non-functional style as well.

Is it possible to do functional programming in a language without functions?

Yes. Method vs function is quite a fine distinction.

It's easy to view each particular method implementation as a function; just have it take as an extra parameter the object on which the method was invoked (if your language doesn't pass it explicitly; not terribly familiar with Ruby). That doesn't quite give you virtual method calls (i.e. where the particular implementation called is determined by the object at runtime). But it's also very easy to imagine a virtual method call as calling a function that just inspects its first parameter (self, this, whatever it's called) and uses it to determine which method implementation to call. With those conventions established, object.method(param1, param2) differs from method(object, param1, param2) only in a trivial syntactic way.

Personally, I view the above as "the truth", and that object-oriented languages just offer syntactic sugar and optimised execution for this because it's such a core part of writing/executing OO programs. That sort of system is also exactly how you do OO when you have functions but not true classes/methods.

It's also trivially easy to implement functions with methods, if you think methods aren't functions. Just have an object with a single method and no attributes! This is also how you do functional programming in languages like Java that insist upon everything being an object and don't let you pass methods/functions as first-class values.

All you need to do functional programming is things you can pass around as first-class values, which can be used to execute code determined by the creator of the "thing" (rather than determined by the code that's using the "thing"), on demand by code that has access to the "thing". I can't think of a programming language that doesn't have this capability.



Related Topics



Leave a reply



Submit