• Nem Talált Eredményt

1. Lists and Set Expressions

1.2. Handling Static Lists

[E || Qualifier_1, Qualifier_2, ...]

Program texts 8.2., and 8.3. shows how to define and handle static lists. This program part binds lists in variables and reuses them in other lists.

8.2. program. Binding lists in variables – Erlang

Data = [{10,20}, {6,4}, {5,2}], List_ = [A, B, C, D],

L = [Data, List_]...

8.3. program. Binding lists in variables – F#

let Data = [(10, 20); (6, 4); (5, 2)]

let List_ = [A, B, C, D]

let L = [Data, List]

There are several tools to create (generate) lists in functional languages. For this purpose we can use recursive functions, list expressions or the library functions of the given language.

1.2. Handling Static Lists

Processing lists. Every L list can be split to a Head element and the rest of the list the Tail. This decomposition and its recursive iteration on the second part of the list ([Head|T ail ] = T ail) enables us to traverse the list recursively. Pattern matching in example 7.4 uses only one element from the beginning of the list but if iterated, it would match the current first element and it would sooner or later process the whole list. However, for the iteration and for the full processing of the list we would need a recursive function.

8.4. program. Pattern matching in lists – Erlang

L = [1,2,3,4,5,6], [Head| Tail] = L...

8.5. program. Pattern matching in lists - F#

let L = [1; 2; 3; 4; 5; 6]

match L with

| Head :: Tail -> …

Note 7.2: Notice that variable Head in program 8.4. contains a data (a number), while Tail contains a list. This is an important detail regarding the further processing of the list, as the beginning and the end of the list should be handled in a different way...

So, the head of the list is always the actual first element and the end is always the list of the remaining elements which can be separated from the beginning and passed on for further processing at the next recursive call of the function with pattern matching.

8.6. program. List traversal with recursive function - Erlang

8.7. program. List traversal with recursive function - Clean

listatr [h:t] = h + listatr t listatr [] = 0

8.8. program. List traversal with recursive function – F#

let rec listatr acc list = match list with

| h :: t -> listatr (acc + h) t | [] -> acc

When reaching a single element list Head gets the only element of the list, while Tail gets the rest, namely an empty list. The empty list is handled by the second clause of the function stopping the recursive execution. In fact, the empty list is the base criterion of the recursion. List elements can be processed, summed or displayed arbitrarily in. Properly written recursive functions do not stop in functional languages, so they can process lists of indefinite length no matter whether we generate or traverse the list. In order to understand the point of

Acc.

Function sum/2 in program 8.9. is a multiple clause function, regarding its structure. The task of the first clause is to split the first element of the list, it got as its parameter, from the rest of the list and bind it in variable Head.

Then, it calls itself with the actual sum, which is the rest of the list. The second clause stops the recursion when the list runs out of elements, namely when the actual (second) parameter is an empty list. We sign the empty list with the [] formula. The return value of the function is the sum of the numbers in the list, which is stored in the Acc and Acc0 variables during the recursive run. Note 7.3.: We need variable Acc0 because ass Acc = Acc + H is a destructive assignment and as such it cannot be used in functional languages… Note 7.4.: If the list given as parameter does not contain numbers, the function still works, but it must contain elements on which the + operator can be interpreted… Let us create the module implementing function sum/2, compile it and call it from the command line (program list 8.12.).

8.14. programlista. Running sum in F# interactive window

val sum : int -> int list -> int > let List = [1; 2; 3; 4];;

val List : int list = [1; 2; 3; 4]

> sum 0 List;;

val it : int = 10

We can generate new lists with recursive functions or transform existing ones bound into a new variable. The parameter of functions carrying out such tasks can be a list (or a construction “producing elements”), and their return value can be another list containing the generated elements.

8.18. program. Generating and concatenating lists - Erlang

8.19. program. Generating and concatenating lists - Clean

8.20. program. Generating and concatenating lists - F#

Function comp2/2 is typical recursive list processing with multiple clauses. The first clause increases the value of the first element in the list in the third parameter by one, then, puts it into the new list which is passed on for the next call. When the list is empty, it stops and returns the result list. Function comp3/3 works similar to function comp2/2. This function can be considered as the general version of comp3/3 as its first parameter is a function expression which is called with every element of the list. This version is more general because it can not only call a certain function with the elements of the list but any kind of a function. Program list 8.21.

contains the implementation of the fully generalized version of the program. This example is in this section to show a common use of higher order functions.

8.21. program. Generalization of a function - Erlang

8.22. program. List with a higher order function – Clean

We can see that the only role of function use/0 is to call function comp3/3 and generate the list.

8.23. program. List with a higher order function - F#

If you want to run this program, compile it and call the use/0 function with the module qualifier (program list 8.24.).

lista = [1,2,3,4]

where plus n = [n+1]

Start = use

If we examine programs 8.21. and 8.18. more closely, we can see that functions comp2/3 and comp3/3 return the same result if the same thing “happens” in function add as in the function expression, however, function comp3/3 can be used for multiple purposes as we can change the function‟s first parameter arbitrarily.

Note 7.5.: Generalization of functions makes our programs more effective and more widely applicable. When there is chance, we should create as generally applicable functions as possible…