Lessons/Functions

From wiki.visual-prolog.com

In the Hello World! lesson we created a predicate that took an argument and passed it on to another predicate. The data was flowing inwards. Here we will extend with data that float outwards.

Let us start by creating a function. A function is a predicate that returns a value to place where the function was called from.

Exercise Add this code to a console project:
class predicates
    makeGreeting : (string Name) -> string Greeting.
clauses
    makeGreeting(Name) = Result :-
        Result = string::format("Hello %!\n", Name).
Build the project, and answer "Yes" to adding the ...string.ph include statement.

Let's start with the include statement. In our new clause we are calling the format predicate in the string class. However the string class is not visible in the main.pro file. At this point we will not concern ourselves with why this is so and what needs to be done, etc. We will simply accept that the Compiler and IDE in collaboration knows how to solve the problem by inserting a suitable include statement in a suitable place. Actually, this "automation" will deal with most "including" that you ever deal with. The back side to this magic (as to all such automation magic) is that, lazy as we are, we don't really get to know the "include stuff", and the day where the magic cannot figure out what to do we don't know it either (see Creating a Package).

Now let us return to the function itself. As mentioned a function is a predicate that returns a value. In the declaration of makeGreeting there is an arrow -> between the arguments and the return type. This arrow indicated that the predicate is a function and the type after the arrow say what type the returned value has. Again the name (i.e. Greeting) after the type mainly serves documentation purposes.

A function clause has the form <head> = <result> :- <body>.. The execution flow is that we "enter" at the <head>, then the <body> is executed and then the <result> is evaluated/executed and returned.

In the clause above the returned value is in the variable Result, which receives it value in the second line (i.e. in the <body> of the clause). What happens in the second line is actually that we call another function, namely the function format in the string class.

The name Result is used just to illustrate that is does not have to be Greeting even though this is what is written in the declaration. (For a real program I would say: why use two quite unrelated words for the same thing.)

The function string::format is closely related to stdio::writef. The input is the same, but stdio::writef will write the result to the standard output stream, string::format returns the result as a string.

Let us call our new function:

Exercise Update the run clause like this:
clauses
    run() :-
        DearGreeting = makeGreeting("Dear"),
        stdio::write(DearGreeting),
        WorldGreeting = makeGreeting("World"),
        stdio::write(WorldGreeting).
Run the project (in a window).

It is worth noticing that equal is a rather special thing in Visual Prolog. In the function clause <head> = <result> :- <body>. it is just a token that separates the head from the result. But in the clause bodies it is an equal operator as you know it from mathematics and logic. Equal is very much unlike an assignement operator as you may know it from other programmig languages. Notice for example that equal is symetrical:

Exercise Update the makeGreeting clause to look like this:
class predicates
    makeGreeting : (string Name) -> string Greeting.
clauses
    makeGreeting(Name) = Result :-
        string::format("Hello %!\n", Name) = Result.
And run the project.

Notice that the result of calling a function is a value, you do not have to bind that value to a variable, you can use it directly.

Exercise Update the makeGreeting clause to look like this:
class predicates
    makeGreeting : (string Name) -> string Greeting.
clauses
    makeGreeting(Name) = string::format("Hello %!\n", Name).
And run the project.

Here we have used the result of the string::format function directly as the result of makeGreeting. As a result we have nothing for the function <body>, but fortunately the function <body> is optional (if there is no <body> then the :- token must also be left out).

In the same way we can use the returned value from makeGreeting directly in a call to stdio::write:

Exercise Update the run clause like this:
clauses
    run() :-
        stdio::write(makeGreeting("Dear")),
        stdio::write(makeGreeting("World")).
Run the project (in a window).

Summary:

  • A function declaration contains an arrow -> followed by the type of the value that the function returns.
  • A function clause has the form <head> = <result> :- <body>.
  • Or the form <head> = <result>. if there is no need for a body.
  • The equal operator is not an assignment operator as known from some other programming lanugages (it is for example symetrical).