0

Representative Functional Languages and Their Features

Functional Languages

Any programming language supports and/or encourages functional programming is called a functional language.

What is functional programming?

A functional program is simply an expression, and executing the program means evaluating the expression.

In imperative programming, execute a function may result in different values in different time. It is because imperative programming relies on modifying the state through a sequence of commands.

In contrast, execute a function f(x) twice in functional code will give the same output in any given time. Since there is no assignment in functional programming, therefore, no variables to assign and no state is changed (no side effect).

Representative Functional Languages

There are more than 20 functional languages you can find here

In this article we will explore an purely functional language (Haskell) and a mix of imperative and functional language (Ruby)

Haskell

Haskell is a purely functional language, which means that in general, functions in Haskell do not have side effects.

Haskell has some handy features:

  • Pattern matching
  • Lazy evaluation
  • List comprehension

Pattern Matching

Haskell has a cool way to construct function by using Pattern Matching. Pattern Matching are ordered set of patterns which data should conform and will be deconstructed accordingly.

In the following code, the data passed to the function will checked against the patterns from top to bottom, and if the pattern is matched, its body will be used.

lottery :: (Integral a) => a -> String
lottery 9 = "Jack pot!"
lottery x = "Sorry, good luck next time!"

So here if you call lottery(5) you will get the message Sorry, good luck next time! because 5 is not matched to 9

Therefore, calling lottery(9) will give out the message Jack pot! because of matched pattern.

Note: If you define a function without catch-all pattern it will crash some time.

sayMyName :: Char -> String
sayMyName 'a' = "Alfred"
sayMyName 'b' = "Bob"
sayMyName 'c' = "Chris"

So when you try to call sayMyName 'y' you will get error Non-exhaustive patterns because of the unexpected input.

By defining functions using separate patterns with their own bodies, programmer can write really tidy and readable code.

Lazy evaluation

Lazy evaluation is a method to evaluate a Haskell program. It means that expressions are not evaluated when they are bound to variables, but their evaluation is deferred until their results are needed by other computations. In consequence, arguments are not evaluated before they are passed to a function, but only when their values are actually used.

In simple term, an argument, inspite of being passed to a function, will not be evaluated until its result is needed in the function. More interestingly, a shared expression will not be evaluated more than once because its result is shared between places in which it is used.

For more of Haskell lazy evaluation check this link

List Comprehension

As you know that in Mathematics there is something called set comprehension which is quite similar to list comprehension.

A set comprehension looks like this:

set comprehension

A set of doubles of natural numbers which are less than or equal to 10.

This set can be expressed by using list comprehension

[x*2 | x <- [1..10]]
[2,4,6,8,10,12,14,16,18,20]

Similar to set comprehension in Mathematics, isn't it?

Let's add condition to the list: tripple of the number is greater than or equal to 12

[x*2 | x <- [1..10], x*3 >= 12]
[8,10,12,14,16,18,20]

More examples of list comprehension can be found here

Ruby

Support Functional programming

Ruby is an imperative language but we can still apply functional principles. It's the developer's choice to assure immutability of data.

For example:

Bad:

balances = {"LeBlanc" => 16000}
balances["Yasuo"] = 20000
balances #=> {"LeBlanc"=>16000, "Yasuo"=>20000}

Good:

balances = {"LeBlanc" => 16000}
all_balances = balances.merge("Yasuo" => 20000) #=> {"LeBlanc"=>16000, "Yasuo"=>20000}

Don't update, create a new one if you're following functional principles.

Ruby has built-in methods with functional approach and its destructive version. Look at the example of select and select!

numbers = [1, 2, 3 ,4]

numbers.select { |num| num > 3 }

numbers #=> [1, 2, 3, 4]

numbers.select! { |num| num > 3 }

numbers #=> [4]

Input should not be updated after executing a function. Again it's the programmer's choice to apply functional approach or not.

Everything is object

Either a piece of information is a string or an integer, that piece of information is an object. An object has its own properties and actions. In Ruby context, properties are instance variables and actions are methods.

For example: an integer can use times method

10.times { print "I am tired of writing this line 10 times \n" }

Observing the ancestors of an integer shows that an integer is a Fixnum and inherited from Object class

10.class
#=> Fixnum

10.class.ancestors
#=> [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]

The same goes for a string

"Hello World".class.ancestors
#=> [String, Comparable, Object, Kernel, BasicObject]

Block

Closure can be attached to any method. A closure in this context is a block and what is a block?

A block is simply code that is inside do and end. There are two ways to write a block

  • do and end code block
  • { } inline code block

We can take an example of Array#select:

[1, 2, 6, 9, 69].select { |number| number > 5 }
#=> [6, 9, 69]

#or
[1, 2, 6, 9, 69].select do |number|
  number > 5
end
#=> [6, 9, 69]

|number| in this example is a block parameter and its value is each number in the array.

Blocks are inspired by functional languages. Matz said, “in Ruby closures, I wanted to respect the Lisp culture.”

Implicit return

In ruby, return is optional unless you want explicit return. The value of the last expression will be the return value of the method.

numbers = [1, 2, 3, 4]

def collect_square numbers
  squares = []
  numbers.each do |num|
    squares << num * num
  end
  squares
end #=> not so good

#Using functional approach and implicit return
def collect_square numbers
  numbers.map { |num| num * num }
end

# Both examples will return [1, 4, 9 ,16]

One application of this feature is method chaining Let's say you have a Car and wants to perform multiple actions

class Car
  attr_accessor: position

  def initialize options = {}
    @position = 0
  end

  def move_forward distance
    self.position += distance
  end

  def move_backward distance
    self.position -= distance
  end
end

You want something like this: Car.new.move_forward(100).move_backward(50)

Simply return self at the end of move_forward and move_backward will do the magic

class Car
...
  def move_forward distance
    self.position += distance
    self
  end

  def move_backward distance
    self.position -= distance
    self
  end
end

Everything is open

You can extend any classes and modules in Ruby, including built-in classes and mdoules. This makes everything open in Ruby.

For example you want to have something like 6.plus(11).minus(4)

module Fixnum
  def plus x
    self.+ x
  end

  def minus x
    self.- x
  end
end

6.plus(11).minus(4)
#=> 13

References

http://www.rubytips.org/2008/04/07/10-unique-ruby-language-features/ https://code.google.com/p/tokland/wiki/RubyFunctionalProgramming http://learnyouahaskell.com/syntax-in-functions


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí