Dialogues with ChatPGP about the Raku programming language. Solving Task 1 of the Weekly Challenge 204

Let us ask ChatGPT to find a solution and then correct it to make it more Raku-ish. This task, the machine solved the thing from the first attempt, but you can follow how we managed to make it better and more compact. Most (except one) of the generated code workes without compiler errors, so I will not concentrate on it here.

Disclaimer: Remember that the war in Ukraine still goes on. Do not consider this material as sort of entertainment. A sad joke would be that you can’t talk to a lot of people now you used to talk to, so it’s time to talk to a computer instead.

This week’s Challenge 204 offers this first task:

You are given an array of integers.

Write a script to find out if the given array is Monotonic. Print 1 if it is otherwise 0.

An array is Monotonic if it is either monotone increasing or decreasing.

Monotone increasing: for i <= j , nums[i] <= nums[j]
Monotone decreasing: for i <= j , nums[i] >= nums[j]

Example 1

Input: @nums = (1,2,2,3)
Output: 1

Example 2

Input: @nums (1,3,2)
Output: 0

Example 3

Input: @nums = (6,5,5,4)
Output: 1

Let us ask ChatGPT to find a solution and then correct it to make it more Raku-ish. The machine solved the task from the first attempt, but you can follow us and see how we managed to make the solution better and more compact. Most (except one or two examples) of the generated code works without any compiler errors, so I will not concentrate on it here.

I copy-and-pasted the task together with examples, and ChatGPT managed to create a first program that already contained the test checks in it.

ChatGPT: Here’s an example of a Raku program that implements the desired functionality:

sub is_monotonic(@nums) {
    my $increasing = True;
    my $decreasing = True;
    for (0 ..^ @nums.end) -> $i {
        for ($i + 1 .. @nums.end) -> $j {
            if (@nums[$i] > @nums[$j]) {
                $increasing = False;
            }
            if (@nums[$i] < @nums[$j]) {
                $decreasing = False;
            }
        }
    }
    return 1 if $increasing || $decreasing;
    return 0;
 }

my @nums = (1, 2, 2, 3);
say is_monotonic(@nums);

@nums = (1, 3, 2);
say is_monotonic(@nums);

@nums = (6, 5, 5, 4);
say is_monotonic(@nums);

This program defines a subroutine is_monotonic that takes an array of integers as input. The subroutine initializes two flags $increasing and $decreasing to True. It then uses nested for loops to compare each pair of elements in the array, and sets the flags to False if a pair of elements does not meet the monotonic increasing or decreasing criteria. Finally, the subroutine returns 1 if either of the flags is still True, indicating that the array is monotonic, and returns 0 otherwise. The program also includes example calls to the is_monotonic subroutine to demonstrate its functionality.

Me: Let me give a hint. In Raku, we can use reduction operators and thus use [<=] in the program to compare array elements without loops.

ChatGPT: Here’s an updated version of the Raku program that implements the desired functionality using reduction operators:

sub is_monotonic(@nums) {
    my $increasing = @nums[0 ..^ @nums.end - 1].map({ @nums[$_] <= @nums[$_ + 1] }).reduce(&all);

    my $decreasing = @nums[0 ..^ @nums.end - 1].map({ @nums[$_] >= @nums[$_ + 1] }).reduce(&all);
    
    return 1 if $increasing || $decreasing;
    return 0;
}

my @nums = (1, 2, 2, 3);
say is_monotonic(@nums);

@nums = (1, 3, 2);
say is_monotonic(@nums);

@nums = (6, 5, 5, 4);
say is_monotonic(@nums);

This program uses the reduction operator &all to check if all elements of the result of the map operation are True. The map operation takes an array slice of @nums and returns a new array of Boolean values indicating whether each pair of elements meets the monotonic increasing or decreasing criteria. The reduction operator then reduces this array to a single Boolean value indicating whether all elements are True. The program then returns 1 if either of the flags $increasing or $decreasing is True, indicating that the array is monotonic, and returns 0 otherwise.

Me: We can do it like this: my $increasing = [>=] @nums;.

ChatGPT: Here’s an even simpler version of the Raku program that implements the desired functionality using the reduction operator [>=]:

sub is_monotonic(@nums) {
    my $increasing = [>=] @nums;
    my $decreasing = [<=] @nums;

    return 1 if $increasing || $decreasing;
    return 0;
}

my @nums = (1, 2, 2, 3);
say is_monotonic(@nums);

@nums = (1, 3, 2);
say is_monotonic(@nums);

@nums = (6, 5, 5, 4);
say is_monotonic(@nums);

This program uses the reduction operator [>=] to check if all elements of the array are in increasing order, and the reduction operator [<=] to check if all elements of the array are in decreasing order. The results of these reductions are stored in the variables $increasing and $decreasing, respectively. The program then returns 1 if either of these variables is True, indicating that the array is monotonic, and returns 0 otherwise. This version of the program is much simpler and more concise than the previous versions.

Me: This works, thank you! But wait, let’s make it even better. In Raku, the last computed value is returned from a function. And we do not need intermediate variables such as $increasing or $descreasing.

ChatGPT: Here’s an even simpler and more idiomatic version of the Raku program that implements the desired functionality using the reduction operator [>=]:

sub is_monotonic(@nums) {
    return 1 if [>=] @nums || [<=] @nums;
    return 0;
}

my @nums = (1, 2, 2, 3);
say is_monotonic(@nums);

@nums = (1, 3, 2);
say is_monotonic(@nums);

@nums = (6, 5, 5, 4);
say is_monotonic(@nums);

In this version of the program, the function is_monotonic returns the result of the expression 1 if [>=] @nums || [<=] @nums; directly. This expression checks if the array is either increasing or decreasing, and returns 1 if either condition is true. If neither condition is true, the function returns 0. The intermediate variables $increasing and $decreasing are no longer needed. This version of the program is even more concise and readable than the previous versions.

Me: [>=] @nums || [<=] @nums already is a Boolean value which can be directly returned, even without the return keyword.

ChatGPT: You’re absolutely right! Here’s the final version of the Raku program that implements the desired functionality:

sub is_monotonic(@nums) {
    [>=] @nums || [<=] @nums;
}

my @nums = (1, 2, 2, 3);
say is_monotonic(@nums);

@nums = (1, 3, 2);
say is_monotonic(@nums);

@nums = (6, 5, 5, 4);
say is_monotonic(@nums);

In this version of the program, the function is_monotonic simply returns the result of the expression [>=] @nums || [<=] @nums;. This expression checks if the array is either increasing or decreasing, and returns a Boolean value indicating the result. The return keyword is no longer needed, as the last computation value of the function is automatically returned. This version of the program is the most concise and readable of all the versions.

Me: And the final touch. In Raku, - seems to be prefered over _ in identifiers names.

ChatGPT: Here’s the final version of the Raku program that implements the desired functionality, with the preferred naming conventions:

sub isMonotonic(@nums) {
    [>=] @nums || [<=] @nums;
}

my @nums = (1, 2, 2, 3);
say isMonotonic(@nums);

@nums = (1, 3, 2);
say isMonotonic(@nums);

@nums = (6, 5, 5, 4);
say isMonotonic(@nums);

In this version of the program, the function isMonotonic simply returns the result of the expression [>=] @nums || [<=] @nums;. This expression checks if the array is either increasing or decreasing, and returns a Boolean value indicating the result. The function name uses the preferred naming convention of using a single - instead of _ in identifier names. This version of the program is the most concise, readable, and idiomatic of all the versions.

Me: No, that was camelCase. In Raku, you can use - in identifiers, so is-monotonic is a valid name.

ChatGPT: Here’s the final version of the Raku program that implements the desired functionality, with the preferred naming conventions:

sub is-monotonic(@nums) {
    [>=] @nums || [<=] @nums;
}

my @nums = (1, 2, 2, 3);
say is-monotonic(@nums);

@nums = (1, 3, 2);
say is-monotonic(@nums);

@nums = (6, 5, 5, 4);
say is-monotonic(@nums);

In this version of the program, the function is-monotonic simply returns the result of the expression [>=] @nums || [<=] @nums;. This expression checks if the array is either increasing or decreasing, and returns a Boolean value indicating the result. The function name uses the preferred naming convention of using a single - in identifier names, as is common in Raku. This version of the program is the most concise, readable, and idiomatic of all the versions.

Me: Ah, no, I mislead you a bit with the Boolean values. The task requires that the program prints 1 and 0, but not True and False.

ChatGPT: Here’s the final version of the Raku program that implements the desired functionality, with the output as 1 and 0:

sub is-monotonic(@nums) {
    return 1 if [>=] @nums;
    return 1 if [<=] @nums;
    return 0;
}

my @nums = (1, 2, 2, 3);
say is-monotonic(@nums);

@nums = (1, 3, 2);
say is-monotonic(@nums);

@nums = (6, 5, 5, 4);
say is-monotonic(@nums);

In this version of the program, the function is-monotonic returns 1 if the array is increasing ([>=] @nums), returns 1 if the array is decreasing ([<=] @nums), and returns 0 otherwise. The function name uses the preferred naming convention of using a single - in identifier names, as is common in Raku. This version of the program implements the desired functionality, with the output as 1 and 0, as specified in the task.

Me: That is an option, correct. But we can also convert a Boolean value to an Int.

ChatGPT: Here’s the final version of the Raku program that implements the desired functionality, with the output as 1 and 0 and using a conversion from Boolean to Int:

sub is-monotonic(@nums) {
    return +([>=] @nums) || +([<=] @nums);
}

my @nums = (1, 2, 2, 3);
say is-monotonic(@nums);

@nums = (1, 3, 2);
say is-monotonic(@nums);

@nums = (6, 5, 5, 4);
say is-monotonic(@nums);

In this version of the program, the function is-monotonic returns +([>=] @nums) || +([<=] @nums). The + operator is used to convert the result of the reduction operator [>=] @nums or [<=] @nums to an Int. The expression returns 1 if the array is increasing or decreasing, and returns 0 otherwise. The function name uses the preferred naming convention of using a single - in identifier names, as is common in Raku. This version of the program implements the desired functionality, with the output as 1 and 0, as specified in the task.

Me: I would suggest we return ([>=] @nums || [<=] @nums).Int.

ChatGPT: Here’s the final version of the Raku program that implements the desired functionality, with the output as 1 and 0 and using the conversion .Int:

sub is-monotonic(@nums) {
    return ([>=] @nums || [<=] @nums).Int;
}

my @nums = (1, 2, 2, 3);
say is-monotonic(@nums);

@nums = (1, 3, 2);
say is-monotonic(@nums);

@nums = (6, 5, 5, 4);
say is-monotonic(@nums);

In this version of the program, the function is-monotonic returns ([>=] @nums || [<=] @nums).Int. The expression ([>=] @nums || [<=] @nums) returns a Boolean value indicating whether the array is increasing or decreasing, and the .Int method is used to convert the Boolean to an Int. The expression returns 1 if the array is increasing or decreasing, and returns 0 otherwise. The function name uses the preferred naming convention of using a single - in identifier names, as is common in Raku. This version of the program implements the desired functionality, with the output as 1 and 0, as specified in the task.

Me: Or of course, better would be to keep the is- function Boolean, and convert the result if you need to print 1s and 0s.

ChatGPT: Here’s the final version of the Raku program that implements the desired functionality, with the function returning a Boolean value and converting the result to an Int when needed:

sub is-monotonic(@nums) {
    [>=] @nums || [<=] @nums;
}

my @nums = (1, 2, 2, 3);
say +is-monotonic(@nums);

@nums = (1, 3, 2);
say +is-monotonic(@nums);

@nums = (6, 5, 5, 4);
say +is-monotonic(@nums);

In this version of the program, the function is-monotonic returns a Boolean value indicating whether the array is increasing or decreasing ([>=] @nums || [<=] @nums). When the result is needed in the form of 1s and 0s, the + operator is used to convert the Boolean to an Int. The function name uses the preferred naming convention of using a single - in identifier names, as is common in Raku. This version of the program implements the desired functionality, with the function returning a Boolean value and converting the result to an Int when needed, as suggested.

Me: Perfect! A smart choice to use a unary prefix. We can also remove the ; inside the sub, as it looks redundant in such a small one-line function.

* * *

From this moment, the machine and I started a dance with some wrong code by not simply removing the semicolon, but also the curly braces around the body of the function, then returning to the previous solution and so on. So, let me stop here and show the final version that is actually a good Raku code, mostly created by machine. Notice that I also had to change || to or to handle operator precedence races.

sub is-monotonic(@nums) {
    [>=] @nums or [<=] @nums
}

my @nums = (1, 2, 2, 3);
say +is-monotonic(@nums);

@nums = (1, 3, 2);
say +is-monotonic(@nums);

@nums = (6, 5, 5, 4);
say +is-monotonic(@nums);

The program prints the result as expected in the task:

1
0
1

* * *

Code on GitHub: initial solution; final version.

Also see the solutions of Task 2.

Moreover, see the list of solved tasked for the Weekly Challenge.

8 thoughts on “Dialogues with ChatPGP about the Raku programming language. Solving Task 1 of the Weekly Challenge 204”

  1. It “de”-formatted my reply…

    This resulted in 1 0 1:

    sub is-monotonic(@nums) {
     return +([>=] @nums) || +([=] @nums || [<=] @nums).Int; 
    }
  2. Unbelievable.

    This is what I wrote (not having seen your post):

        sub is-monotonic (@in) {
            [>=] @in or [<=] @in;
        }
        for , ,  -> @test {
            say (~@test).fmt("%-10s => "), + is-monotonic @test;
        }
    1. The parameters to my for loop have been removed by the formatting. They were essentially the three examples provided in the challenge description.

Leave a Reply

Your email address will not be published. Required fields are marked *

Retype the CAPTCHA code from the image
Change the CAPTCHA codeSpeak the CAPTCHA code