Sei sulla pagina 1di 6

Asian Journal of Computer Science And Information Technology 6:1 (2016) 1 -6.

Contents lists available at www.innovativejournal.in

Asian Journal of Computer Science And Information Technology

Journal Homepage: http://innovativejournal.in/ajcsit/index.php/ajcsit

FUNCTIONAL PROGRAMMING IN C++14

Austin Owino Wetoyi

Vrije Universiteit, Faculty of Science and Bio-Engineering Sciences, Department of Computer Science, Brussels, Belgium

ARTICLE INFO ABSTRACT


Corresponding Author: Although all programmers familiar with the C++ computer programming
Austin Owino Wetoyi language will unanimously agree that the language is a multi-paradigm
Vrije Universiteit, Faculty of language, not many are aware that it sufficiently supports writing programs in
Science and Bio-Engineering the functional style or logic style.
Sciences, Department of One of the tragic consequences of lack of this knowledge is that there are few
Computer Science, Brussels, computer programming lecturers in our universities who can teach functional
Belgium programming. A typical programming lecturer (familiar with C++) assumes that
research@austinowino.com to teach functional programming, one must learn a language specifically
designed for functional programming (such as ML and Haskell) and very few
Keywords C++, functional are ever eager to learn a new language from scratch. This may explain why
programming, programming most of our universities don’t have functional programming in their curriculum
paradigm, logic programming or if it is there, then it is an elective course that is rarely if ever taught.
In this paper, I highlight C++ language’s support for the functional
programming style. I explore some functional programming concepts and
illustrate how each can be accomplished in C++. It is my hope that this paper
DOI:http://dx.doi.org/10.15520 will bring back this beautiful paradigm into our universities’ curricula. I also
/ajcsit.v6i1.39 hope that those who use the other paradigms of C++ for example in software
development will realize that they can also write most of the code using the
functional style.
©2016, AJCSIT, All Right Reserved.
1. THE C++14 STANDARD
Modern C++, as defined in the C++11 standard has (since C++11), 2016).
evolved to become analgorithmic language. This 2. WHAT IS FUNCTIONAL PROGRAMMING?
represents as much an idiomatic departure from Object In computer science, functional programming is a
Orientation as C++ was a departure from C’s procedural programming paradigm that treats computation as the
top-down composition. “C++11 feels like a new language,” evaluation of expressions (functions) and avoids state
says Bjarne Stroustrup (Stroustrup). and mutable data. In Functional programming, programs
In C++14, the need for templates when writing functions are executed by evaluating expressions. It emphasizes the
has been done away with competently making the number application of functions, in contrast to the imperative
of lines you write to accomplish a task much fewer than programming style, which emphasizes changes in state;
before. The following is an example of a generic function in with imperative programming, programs are composed of
the C++11 standard that returns a value that is more than statements which change global state when executed
its argument by one. This example obtained from (Wikipedia, Monad (functional programming), 2016).
(Kohlhepp). Because in functional programming programs are
struct xplusone { executed by evaluating expressions (functions), functional
template <typename T> programming tries to focus on the what rather than the
auto operator ()(const T& x) const->decltype (x+1) { how of problem solving. That is, a functional program
return x + 1; should describe the problem to be solved rather than
}; focus on the mechanism of solution.
}xplusone; 3. SOME BENEFITS OF FUNCTIONAL PROGRAMMING
The equivalent in function in C++14 standard is Functional design may seem like an odd constraint to
auto xplusone = [] (auto x) { work under. Why should you avoid objects and side
return x + 1; effects? There are theoretical and practical advantages to
}; the functional style:
The C++14 version uses a lambda expression which is 4.1 Shorter code
the way to create anonymous functions. The function Functional program codes are often shorter, more
returned by the lambda expression is assigned to the reliable and easier to understand than their equivalent
variable xplusone. Therefore,the variable xplusone is a imperative counterparts. Since various studies have
function that takes one argument of any type; the auto shown that the average programmer's productivity in
keyword implies this (cppreference.com, auto specifier terms of lines of code is more or less the same for any

1
Austin /Functional Programming in C++14

programming language, this translates also to higher different approach. However, C++ (along with Lisp, and
productivity (Haskell.org, Functional programming, 2014). Python among others) is a multi-paradigm language. It
4.2 Modularity supports several different approaches to writing a
A more practical benefit of functional programming is program; you can write programs or libraries that are
that it forces you to break apart your problem into small largely procedural, object-oriented, or functional in all of
pieces. Programs are more modular as a result. It's easier these languages. In a large program, different sections
to specify and write a small function that does one thing might be written using different approaches; the GUI
than a large function that performs a complicated might be object-oriented while the processing logic is
transformation. Small functions are also easier to read and procedural or functional, for example.
to check for errors (Ltd). 4.6 The auto keyword
4.3 Ease of debugging and testing The auto keyword when used as data type for an
Testing and debugging a functional-style program is identifier means that the exact data type of the identifier
easier. will be deduced by the compiler from the type of the
Debugging is simplified because functions are expression used to generate the result (cppreference.com,
generally small and clearly specified. When a program auto specifier (since C++11), 2016).
doesn't work, each function is an interface point where auto x = 1; //data type of ex is int
you can check that the data are correct. You can look at the auto f() { return x; } // return type is int
intermediate inputs and outputs to quickly isolate the const auto& f() { return x; } // return type is const int&
function that's responsible for a bug. auto f() {} // returns void
Testing is easier because each function is a potential auto g() { return f(); } // returns void
subject for a unit test. Functions don't depend on system The auto keyword enables us to write generic
state that needs to be replicated before running a test; functions, for example the following code will compile.
instead you only have to synthesize the right input and auto identity (auto x) { return x; }
then check that the output matches expectations (Ltd). std::cout << identity(34) << std::endl;
4.4 Composability std::cout << identity(3.4) << std::endl;
As you work on a functional-style program, you'll write std::cout << identity("hello world") << std::endl;
a number of functions with varying inputs and outputs. std::cout << identity('Q') << std::endl;
Some of these functions will be unavoidably specialized to In the following sections we look at some functional
a particular application, but others will be useful in a wide programming features and for each, show how C++
variety of programs. For example, a function that takes a supports the feature.
directory path and returns all the XML files in the 4.7 First-class functions
directory, or a function that takes a filename and returns The terminology "first-class" is a computer science
its contents, can be applied to many different situations. describes programming language entities that have no
Over time you'll form a personal library of utilities. restriction on their use, thus first-class functions can
Often you'll assemble new programs by arranging existing appear anywhere in the program that other first-class
functions in a new configuration and writing a few entities like numbers can, including as arguments to other
functions specialized for the current task (Ltd). functions and as their return values i.e. they can be passed
4.5 Structured Programming around within program in much the same way as other
Functional programming is known to provide better variables (Haskell.org, Functional programming,
support for structured programming than imperative What_is_functional_programming).
programming. To make a program structured it is We will see this as we cover the other features.
necessary to develop abstractions and split it into 4.8 Lambda and Anonymous functions
components which interface each other with those In functional programming, a function definition can be
abstractions. Functional languages aid this by making it applied without having its identity known; i.e. a function
easy to create clean and simple abstractions. It is easy, for can be anonymous. In C++, you create an anonymous
instance, to abstract out a recurring piece of code by function using a lambda expression. The syntax for of a
creating a higher-order function which will make the lambda expression is
resulting code more declarative and comprehensible [capture-list](arguments)->return type {function body}
(Haskell.org, Functional programming, 2014). You can apply the function the expression returns
4. SOME FEATURES OF FUNCTIONAL LANGUAGES straight away. For example, the following statement would
A programming paradigm would simply be defined display 56 on the scree.
as the way a programming language supports [](int x)->void {std::cout << x << std::endl;} (56);
decomposition of a problem. Functional programming The lambda expression is evaluated at compile time.
decomposes a problem into a set of functions. Ideally, For an anonymous function to be used elsewhere (i.e.
functions only take inputs and produce outputs, and don't not where it is defined) the block that has created function
have any internal state that affects the output produced passes it to the block of code that needs to use it. This is
for a given input. the way anonymous function as most commonly used in
A number of concepts and paradigms are specific to functional programming. An example is shown in the
functional programming, and generally foreign to feature, closure section.
imperative programming (including object oriented 4.9 Closure
programming). In this section we briefly discuss some of Being first-class also means that it is possible to define
these concepts and then show how C++ implements them. and manipulate functions nested in code blocks. Such a
The designers of some computer languages have nested function can be passed to another block of code, for
chosen one approach to programming that's emphasized. the receiving block to execute when it deems fit. But, as
This often makes it difficult to write programs that use a well as being a code block amenable to being passed

2
Austin /Functional Programming in C++14

around for deferred execution, it also carries the context in 4.11 Higher-order functions (HOFs)
which it was defined, and thus can reference variables, etc. A higher-order function is a function which does at least
from that context. Such a function is said to close over the one of the following (Wikipedia, Map (higher-order
environment in which it was created and is known as a function)):
closure. So simply a closure is a function defined in a code  takes one or more functions as an input
block, can be passed to another function and wherever it (arguments)
lands, it can still remember the code block it was created  outputs (returns) a function.
in. The following is a higher order function. It takes three
The variable(s) from the context of the closure that it arguments one of which is a binary function and applies
can access while executing wherever it lands is are “bound the function (the third argument) to the two arguments.
in”in the closure function. The closure is “closed over a auto binaryAdder = [](auto arg1, auto arg2){ return arg1 +
free variable(s)” – hence the term closure. In other words, arg2; };
a closure is a function that makes use of free variables in auto aHoF = [](auto arg1, auto arg2, arg3) {
its definition. It 'closes' around some portion of its return arg3(arg1 + arg2);
environment (Haskell.org, Closure, 2010). The closure is };
constructed by returning it from another function which int x = aHoF(5, 3, binaryAdder); //applies binaryAdder to
creates the binding. 3 and 5
A simple example will illustrate this. The outer Function The value assigned to the variable x is 8, the sum of 5
in the code below is assigned a function that defines and and 3.
returns another function. The outerFunction is therefore 4.12 map, filter and fold
also the context of the nested function that is returned. Where a traditional imperative program might use a
The nested function can access the argument of the outer loop to traverse a list, a functional style would often use a
function. The call to outerFunction returns the inner higher-order function for example, map, a filter or a fold.
function with outerArg bound to the innerFunction. The map is the name of a higher-order function that applies
variable innerFunction is then a function that takes one a given function element-wise to a list of elements and
argument and returns the sum of 39 and that argument. returns a list of results. Typically,map takes a function and
auto outerFunction = [](auto outerArg) a list as its arguments, applies the function to each element
{return [=] (int innerArg)->auto{ return outerArg + of the list and returns the list as its result. The C++’s
innerArg; }; standard library contains lots of these functions. Some are
}; mutating algorithms (transform their list arguments) and
auto innerFunction = outerFunction(39); others non-mutating algorithms. The transform algorithm
std::cout << innerFunction(12) << std::endl; // output is applies the function argument it receives to a range/list of
51 values. Here is an example from (Wikipedia, Map (higher-
Note: In C++, closures do not extend the lifetime of order function))using a vector as the list.
their context. (If you need this, use you use shared_ptr) auto outerFunction = [](auto outerArg) {
(Tambe) return [=] (auto innerArg){ return outerArg + innerArg;
Note: In a function declaration which does not use the };
trailing return type syntax, the keyword auto indicates };
that the return type will be deduced from the operand of std::vector<int> vec(5,13); //5 int elements, all equal to 13
its return statement using the rules for template argument std::vector<int>::iterator it;
deduction. for (it = vec.begin(); it != vec.end(); it++)
Note: The term closure is often mistakenly used to std::cout << *it << " "; std::cout << std::endl;
mean anonymous function. This is probably because most vec[3] = 6;
languages implementing anonymous functions allow them auto innerFunction = outerFunction(9);
to form closures and programmers are usually introduced std::transform(vec.begin(),vec.end(),vec.begin(),innerFunc
to both concepts at the same time. These are, however, tion);
distinct concepts. A closure retains a reference to the for (it = vec.begin(); it != vec.end(); it++)
environment at the time it was created (for example, to std::cout << *it << " "; std::cout << std::endl;
the current value of a local variable in the enclosing scope) Higher-order functions are very useful for refactoring
while a generic anonymous function need not do this. [5] code and reduce the amount of repetition.
4.10 Partial Application The output of the above code is
Partial application (or partial function application) 13 13 13 13 13
refers to the process of fixing a number of arguments to a 22 22 22 15 22
function, producing another function of smaller arity The map is an in-place operation; it returns a
(Wikipedia, Partial application). modification of its input. A filter is like a map because its
The function call to outerFunction in the example output is a list, but unlike a map, a filter is noninvasive; it
given above is an example of partial application of a leaves its list input intact. Instead, it produces another list
function. The full application requires a call to the function whose members are only the members of the original list
it returns. An example of a full application is that pass a test. It filters out the elements in a list that
int x = outerFunction(12)(6); //value of x becomes 12 + 6 don’t pass a test. This function is pure. It does not modify
which is 18 the array it is given (Wikipedia, Filter (higher-order
If you call it with one argument, you get a special function)).
version of it that has the first argument bound, and The fold, also known variously as reduce, accumulate,
waiting for the second argument for full application; you compress or inject, is a family of higher-order functions
get a closure. that process a data structure in some order and build up

3
Austin /Functional Programming in C++14

a return value. A fold is a way of getting a single value by }


operating on a list of values (Haskell.org, Fold, 2015). }
In the functional world (as opposed to the mostly std::cout << curr(trebleAdder)(2)(1)(6)(3) << std::endl;
imperative world), folding a list is the only way to, //ouput: 12
collapse or reduce (or "fold") a list into a single value. Note: Functional programming languages implement
Since the list is transformed into a single value, the fold the lambda calculus (Wikipedia, Lambda calculus).In
function is a special type of transformer called a lambda calculus,a function take a single argument only.
consumer.The abstract reasoning behind list consumers is 4.14 Monads
“if we can do something to the first item in the list and the A monad is a structure that represents computations
first item in the rest of the list, then we can do something defined as sequences of steps: a type with a monad
to the whole list”.This is actually a very useful and structure defines what it means to chain operations, or
important concept in computer science. Whenever you nest functions of that type together. This allows the
have anything that can be viewed as a list (whether or not programmer to build pipelines that process data in a
it actually is a list), you can "consume" it using this series of steps (also called actions), in which each action is
principle. decorated with additional processing rules provided by
Typically, a fold deals with two things: the monad (Haskell.org, Monad tutorials timeline, 2015).
 a combining function and Some people tend to think of monads as “chainable state
 a data structure, typically a list of elements. containers.”
The fold then proceeds to combine elements of the data A monad is created by defining a type constructor M
structure using the function in some systematic way. and two operations, bind and return (where return is often
Typically, most for loops can be expressed using maps or also called unit):
folds.  The return operation takes a value from a plain
There are many algorithms in the standard library that type and puts it into a container using the constructor,
are consumers. All of them are non-mutating i.e. they don’t creating a monadic value: M a.
modify their arguments.  The bind operation which takes as its arguments a
An example is in the standard library of C++ is the monadic value M a and a function (a → M b) that can
count_if algorithm which returns the number of elements transform the value.
in its list argument for which its third argument - The bind operator unwraps the plain value a embedded
(predicate) returns true. This example uses a lambda in its input monadic value M a, and feeds it to the function.
expression to count elements divisible by 3 - The function then creates a new monadic value M b that
(cppreference.com, std::count, std::count_if). can be fed to the next bind operators composed in the
int data[] = { 1, 2, 3, 4, 4, 3, 7, 8, 9, 10 }; pipeline.
std::vector<int> v(data, data+10); With these elements, the programmer composes a
int t = std::count_if(v.begin(), v.end(), [](int i) {return i % 3 sequence of function calls (the "pipeline") with several
== 0;}); bind operators chained together in an expression. Each
std::cout << "number divisible by three: " << t << '\n'; function call transforms its input plain type value, and the
; bind operator handles the returned monadic value, which
The output of the above code is is fed into the next step in the sequence. Between each
number divisible by three: 3 pair of composed function calls, the bind operator can
4.13 Currying inject into the monadic value some additional information
Currying is the technique of transforming a function that is not accessible within the function, and pass it along.
that takes multiple arguments in such a way that it can be It can also exert finer control of the flow of execution, for
called as a chain of functions, each with a single argument. example by conditionally calling the function only under
Each application (call) returns a new function if any some conditions, or executing the function calls in a
arguments are still needed to accepts the next argument. particular order (Wikipedia, Monad (functional
Consider the following function which returns the sum programming), 2016).
of its four arguments. This code below illustrates these components. The
auto trebleAdder = [](auto p, auto q, auto r, auto s){ constructor for the monadic value returns a closure which
return p + q + r + s; simply returns the plain value it captures from the
}; constructor. In the appendix, they are included in a full
Currying the above function means we transform it program.
into a function that takes one argument at a time. Here is auto monadicValueConstructor = [] (auto plainValue) {
the transformation return [=] {
auto trebleAdder = [](auto p, auto q, auto r, auto s){ return plainValue;
return p + q + r + s; };
}; };
auto curry = [](auto f){ auto transformFunction = [] (auto plainValue){
return [](auto a){ std::cout << plainValue << std::endl;
return [](auto b){ auto newValue =
return [](auto c){ monadicValueConstructor(plainValue+3); //new monadic
return [](auto d){ value
return f(a) return [=] (auto aBindOp){
} return aBindOp(newValue);
} };
} };

4
Austin /Functional Programming in C++14

auto bindOperation = [] (auto monadicValue) { Most training institutions use C++ specially to teach
return [=] (auto transform){ OOP and sometimes procedural programming. I hope the
//line below feeds plain value into the transformation readersof this paper especially trainers and curriculum
function makers will see that C++ can adequately be used to teach
return transform(monadicValue()); the functional programming paradigm too and bring back
}; functional programming into their curricula if it is not
auto returnOperation = [] (auto plainValue){ there or lift it from obscurity if it is there.
return [=] (auto aBindOp){ REFERENCES
return [1] B. Stroustrup, "C++11 - the new ISO C++ standard,"
aBindOp(monadicValueConstructor(plainValue)); Columbia University, [Online]. Available:
}; http://www.stroustrup.com/C++11FAQ.html. [Accessed
}; 18 March 2016].
[2] C. Kohlhepp, "Chris Kohlhepp's Blog," [Online].
4.15 Recursion Available: https://chriskohlhepp.wordpress.com/lambda-
Recursive functions invoke themselves, allowing an over-lambda-in-cplusplus14/. [Accessed 18 March 2016].
operation to be performed over and over. Recursion is [3] cppreference.com, "auto specifier (since C++11),"
heavily used in functional programming as it is the cppreference.com, 25 January 2016. [Online]. Available:
canonical and often the only way to iterate (loop) http://en.cppreference.com/w/cpp/language/auto.
(Haskell.org, Functional programming, Recursion, 2016). [Accessed 18 March 2016].
Loops are naturally expressed using tail recursion. A [4] Wikipedia, "Monad (functional programming),"
tail recursion is characterised by the use of only one Wikipedia, 23 February 2016. [Online]. Available:
recursive call at the very end of a function https://en.wikipedia.org/wiki/Monad_%28functional_pro
implementation. In other words, when the call is made, gramming%29. [Accessed 19 March 2016].
there are no other statements left to be executed by the [5] Haskell.org, "Functional programming," Haskell.org, 24
function; the recursive call is not only the last statement, December 2014. [Online]. Available:
but there are no earlier recursive calls, direct or indirect. https://wiki.haskell.org/Functional_programming.
Is there any advantage in using tail recursion over [Accessed 18 March 2016].
iteration? In languages such as C++, there may be no [6] A. S. P. Ltd, "Fuctional programming Languages,"
compelling advantage, but in a language such as Prolog, Augment Systems Pvt. Ltd , [Online]. Available:
which has no explicit loop construct (loops are simulated http://www.assignmenthelp.net/pg/functional_program
by recursion), tail recursion acquires a much greater ming_languages. [Accessed 18 March 2016].
weight. In languages endowed with a loop or its [7] Haskell.org, "Functional programming,
equivalents such as an if statement combined with a go to What_is_functional_programming," Haskell.org, [Online].
statement, tail recursion should not be used (Drozdek, Available:
2005). https://wiki.haskell.org/Functional_programming#What_i
Recursion in C++ is straight forward. You simply write s_functional_programming.3F. [Accessed 18 March 2016].
code that make function call to the function whose body [8] Haskell.org, "Closure," Haskell.org, 29 September 2010.
the code appears in. The code below prints 1, 2, 3, 4, 5, 6, 7, [Online]. Available: https://wiki.haskell.org/Closure.
8, 9, using the for loop construct. [Accessed 18 March 2016].
for (int i =1; i < 10; i++) std::cout << i << “, “; [9] S. Tambe, "C++ Truths," [Online]. Available:
This can be achieved using recursion. The function http://cpptruths.blogspot.be/2014/03/fun-with-
below will produced the same output if called as lambdas-c14-style-part-1.html . [Accessed 18 March
printSerial(10). 2016].
void printSerial(int x) [10]
{ Wikipedia, "Partial application," Wikipedia, [Online].
if (x > 0) Available:
{ https://en.wikipedia.org/wiki/Partial_application.
printSerial(x - 1); [Accessed 18 March 2016].
std::cout << x << “, “; [11] Wikipedia, "Map (higher-order function)," Wikipedia,
} [Online]. Available:
else https://en.wikipedia.org/wiki/Map_%28higher-
return; order_function%29. [Accessed 19 March 2016].
} [12] Wikipedia, "Filter (higher-order function),"
5. CONCLUSION Wikipedia, [Online]. Available:
C++ is a really a big language. One should choose the https://en.wikipedia.org/wiki/Filter_%28higher-
most suitable features when writing a program. There are order_function%29. [Accessed 19 March 2016].
many choices to make depending on what kind of program [13] Haskell.org, "Fold," Haskell.org, 17 June 2015.
you are writing. The choice should be influenced by [Online]. Available: https://wiki.haskell.org/Fold.
whether you are building components or writing a [Accessed 19 March 2016].
program that uses component. [14] cppreference.com, "std::count, std::count_if,"
Into this mix of choices is also the programming style cppreference.com, [Online]. Available:
you use. As I have illustrated in this paper, functional http://en.cppreference.com/w/cpp/algorithm/count.
programming has its advantages and in a large program, [Accessed 19 March 2016].
different sections might be written using different [15] Wikipedia, "Lambda calculus," Wikipedia, [Online].
programming styles. Available:

5
Austin /Functional Programming in C++14

https://en.wikipedia.org/wiki/Lambda_calculus. [19] Wikipedia, "Functional programming," Wikipedia,


[Accessed 19 March 2016]. [Online]. Available:
[16] Haskell.org, "Monad tutorials timeline," Haskell.org, https://en.wikipedia.org/wiki/Functional_programming.
28 November 2015. [Online]. Available: [Accessed 18 March 2016].
https://wiki.haskell.org/Monad_tutorials_timeline. [20] Wikipedia, "Higher-order function," Wikipedia,
[Accessed 19 March 2016]. [Online]. Available: https://en.wikipedia.org/wiki/Higher-
[17] Haskell.org, "Functional programming, Recursion," order_function. [Accessed 19 March 2016].
Haskell.org, 23 February 2016. [Online]. Available: [21] K. Henney, "The Miseducation of C++," April 2001.
https://wiki.haskell.org/Functional_programming#Recurs [Online]. Available: http://www.two-
ion. [Accessed 19 March 2016]. sdg.demon.co.uk/curbralan/papers/TheMiseducationOfC
[18] A. Drozdek, Data Structures and Algorithms in C++, ++.pdf. [Accessed 19 March 2016].
3rd Edition, Boston: Thomson Course Technology, 2005.

Appendix
The code below is the one that illustrates monads. It contains the essential components of a monad and the main function.
#include <iostream>
auto monadicValueConstructor = [] (auto plainValue) {
return [=] {
return plainValue;
};
};
auto transformFunction = [] (auto plainValue){
std::cout << plainValue << std::endl;
auto newValue = monadicValueConstructor(plainValue+3); //new monadic value
return [=] (auto aBindOp){
return aBindOp(newValue);
};
};
auto bindOperation = [] (auto monadicValue) {
return [=] (auto transform){
//line below feeds plain value into the transformation function
return transform(monadicValue());
};
auto returnOperation = [] (auto plainValue){
return [=] (auto aBindOp){
return aBindOp(monadicValueConstructor(plainValue));
};
};
int main(int argc, char **argv)
{
auto plainValue = 45; //plain value, a
returnOperation(plainValue)
(bindOperation)(transformFunction)
(bindOperation)(transformFunction)
(bindOperation)(transformFunction);
return 0;
}
Output

How to cite Article: WETOYI, Austin Owino. FUNCTIONAL PROGRAMMING IN C++14. Asian Journal of Computer
Science and Information Technology, [S.l.], v. 6, n. 1, p. 1-6, apr. 2016. ISSN 2249-5126. Available at:
<http://innovativejournal.in/ajcsit/index.php/ajcsit/article/view/39>. Date accessed: 10 Apr. 2016.
doi:10.15520/ajcsit.v6i1.39.

Potrebbero piacerti anche