Debug "if statements"

4 views
Skip to first unread message

Wink Saville

unread,
Jun 16, 2020, 5:56:56 PM6/16/20
to Curv
I'm trying to debug an if statement and got it working several different ways, but why doesn't the code on line 40 work?

Note: the code in line 40 is similar to line 37, which does work.

$ curv -l maxX.debug.curv
top mx=-inf
_mx=-0.5
ERROR: not an expression
at file "maxX.debug.curv":
40|           if (xy[X] > mx) let _mx = xy[X] in do print "_mx=$_mx"; in mx := _mx;
                                                                         ^^^^^^^^^
at file "maxX.debug.curv":
48|     >> extrude (maxX(airfoil) * 10)
                    ^^^^^^^^^^^^^


$ cat -n maxX.debug.curv
     1 let
     2  airfoil = [
     3       [-0.5, 0]
     4      ,[0, 1]
     5      ,[0.5, 0]
     6      ,[0.2, 1]
     7      ,[0, 2]
     8  ];
     9
    10  // Define function to find maximum between 2 values
    11  maxV [v1, v2] =
    12    if (v1 > v2)
    13      do print "$v1 > $v2"; in v1
    14    else
    15      do print "$v2 >= $v1"; in v2;
    16
    17  // Define function to find maximum X value in array v
    18  maxX v =
    19    let
    20      mx=-inf;
    21    in
    22      do
    23        print "top mx=$mx";
    24
    25        for (xy in v)
    26          //mx := if (xy[X] > mx) xy[X] else mx;
    27
    28          //mx := maxV [xy[X], mx];
    29
    30          //mx := if (xy[X] > mx)
    31          //        do print "xy[X]:$(xy[X]) > mx:$mx"; in xy[X]
    32          //      else
    33          //        do print "mx:$mx >= xy[X]:$(xy[X])"; in mx;
    34
    35          //if (xy[X] > mx) mx := xy[X];
    36
    37          //if (xy[X] > mx) let _mx = xy[X] in mx := _mx;
    38
    39          // FAILS
    40          if (xy[X] > mx) let _mx = xy[X] in do print "_mx=$_mx"; in mx := _mx;
    41
    42        print "done mx=$mx";
    43      in
    44        mx;
    45 in
    46  polygon airfoil
    47    // Use the function
    48    >> extrude (maxX(airfoil) * 10)

Doug Moen

unread,
Jun 16, 2020, 7:55:20 PM6/16/20
to Curv
On Tue, Jun 16, 2020, at 9:56 PM, Wink Saville wrote:
I'm trying to debug an if statement and got it working several different ways, but why doesn't the code on line 40 work?

Note: the code in line 40 is similar to line 37, which does work.

A 'let' phrase can be used in two different ways:
    let <definitions> in <expression>
    let <definitions> in <statement>

However, a 'do' phrase can only be used in this one way:
    do <statements> in <expression>

You tried to put 'mx := _mx' after a do, and this is an assignment statement, not an expression.
(Hence the error message "not an expression".)
The reason I don't allow
   do <statements> in <statement>
is that I couldn't think of a reason why anybody would write this.
Because this can be replaced by
   ( <statements> ; <statement> )
It's a compound statement, which is found in almost every imperative programming language.

Thanks for posting this, it is valuable for me to see what kinds of errors people encounter when using Curv.

I can address this problem in one of two ways.

1. I can extend 'do' to be more consistent with 'let', and allow 'do <statements> in <statement>'.
Perhaps more internal consistency will lead to fewer surprises.

2. Or, I can issue a better error message. Something like this:

ERROR: Phrase following 'do...in' is not an expression.
You wrote: 'do <statement-list> in <statement>'. This isn't supported.
You should replace this with '(<statement-list>; <statement>)'.

What do you think?

Perhaps a bigger issue is that the documentation could be improved on the style and idioms you use when writing Curv code. More comments below.
Curv already has a function called 'max'. It takes a list of numbers as an argument, and returns the maximum value. It does the same thing as both maxV and maxX in your program.

Here's a REPL session to illustrate. You can type 'curv' in the shell, with no arguments, and try this code yourself.

curv> max [1,2]
2
curv> max [1,2,3]
3
curv> a = [1,2,3]
curv> a
[1,2,3]
curv> max a
3

The way 'max' works could be surprising to people who are only familiar with languages like Javascript and Python, so  I should explicitly document the thinking and coding style behind functions like 'max'.

If max didn't exist and I wanted to implement it using imperative style, I would write:
  max v =
    do
      local mx = -inf;
      for (x in v)
        if (x > mx) mx := x;
    in mx;
In other words, the entire body of the function is a do...in... expression. Within a 'do', I use 'local' to define local variables, and (stmt; stmt; stmt) is a compound statement. The nice thing about 'local' is that you can freely intermix local statements with other statements, without creating a new level of nesting (as is required when you use 'let').

This is another thing that could be more clearly documented.

Wink Saville

unread,
Jun 16, 2020, 9:54:21 PM6/16/20
to Doug Moen, Curv
On Tue, Jun 16, 2020 at 4:55 PM Doug Moen <do...@moens.org> wrote:
On Tue, Jun 16, 2020, at 9:56 PM, Wink Saville wrote:
I'm trying to debug an if statement and got it working several different ways, but why doesn't the code on line 40 work?

Note: the code in line 40 is similar to line 37, which does work.

A 'let' phrase can be used in two different ways:
    let <definitions> in <expression>
    let <definitions> in <statement>

However, a 'do' phrase can only be used in this one way:
    do <statements> in <expression>

You tried to put 'mx := _mx' after a do, and this is an assignment statement, not an expression.
(Hence the error message "not an expression".)
The reason I don't allow
   do <statements> in <statement>
is that I couldn't think of a reason why anybody would write this.
Because this can be replaced by
   ( <statements> ; <statement> )
It's a compound statement, which is found in almost every imperative programming language.
 
Interestingly, I wasn't aware that you can use parentheses to group multiple statements. On first
blush it seems weird, because using parentheses makes it look like an expression.


Thanks for posting this, it is valuable for me to see what kinds of errors people encounter when using Curv.

I can address this problem in one of two ways.

1. I can extend 'do' to be more consistent with 'let', and allow 'do <statements> in <statement>'.
Perhaps more internal consistency will lead to fewer surprises.

2. Or, I can issue a better error message. Something like this:

ERROR: Phrase following 'do...in' is not an expression.
You wrote: 'do <statement-list> in <statement>'. This isn't supported.
You should replace this with '(<statement-list>; <statement>)'.

What do you think?

If my only choice is 1 or 2, I vote 1, at the moment.
 

Perhaps a bigger issue is that the documentation could be improved on the style and idioms you use when writing Curv code. More comments below.

Documentation can always be improved and style and idioms would be great. As I mentioned before
I think "every" example in the documentation should be executable using suggested idioms.
Got it, so I assume "x" is always local to the for loop?

 

In other words, the entire body of the function is a do...in... expression. Within a 'do', I use 'local' to define local variables, and (stmt; stmt; stmt) is a compound statement. The nice thing about 'local' is that you can freely intermix local statements with other statements, without creating a new level of nesting (as is required when you use 'let').

This is another thing that could be more clearly documented.

Actually, having "expressions", "statements", "actions" and then "let" "do" and "parentheses"
for grouping them is confusing. I'd prefer just "everything is an expression" and there be just
one "grouping" mechanism. Simpler is better, IMHO. Maybe this suggestion isn't possible, but
I think you'd agree having so many similar concepts makes learning harder and arguably makes
bugs more likely.
Reply all
Reply to author
Forward
0 new messages