Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a possibility of multiple statements inside a conditional statement's body?

I'm primarily a C++ (thus an OO/imperative) programmer and I find it quite bizarre that you can only have one statement per evaluation in a conditional statement such as an if-statement in Scheme, a functional language.

For example:

 (let ((arg1 0) (arg2 1))
   (if (> arg1 arg2)
       arg1
       arg2)))

Erroneous example:

(let ((arg1 0) (arg2 1))
  (if (> arg1 arg2)
      (arg1 (display "cool"))
      (arg2 (display "not cool"))))

gives me an error of a type "procedure application: expected procedure, given: 2; arguments were: #void"

That can be solved by placing that said conditional statement into different statements within a body of a defined function for example, with the conditional statement's body having separate statements every time as follows:

(if (condition) statement1a statement2a)
(if (condition) statement1b statement2b)

and so on...

It goes without saying that it's not too practical. Not to mention the duplicated code overhead.

Am I missing anything here or is there really no other way?

like image 693
Alex D. Avatar asked Jun 29 '12 14:06

Alex D.


People also ask

How many if statements can you have in a conditional statement?

Excel allows a max of 7 nested if statements. If we wanted to expand our list of possible statuses, we could add only one more condition and one more status.

Can you have multiple Elseif statements?

You can have as many else if statements as necessary. In the case of many else if statements, the switch statement might be preferred for readability.

How do you execute more than one statement when a condition is true?

If you want to execute multiple statements for the else condition, enclose the code in curly brackets. If you only need to execute a single statement for the else condition, you do not need to use curly brackets.

Can you have multiple conditions in an if statement in C?

A nested if in C is an if statement that is the target of another if statement. Nested if statements mean an if statement inside another if statement. Yes, both C and C++ allow us to nested if statements within if statements, i.e, we can place an if statement inside another if statement.


4 Answers

Since you are already using an iterative process in the "inner" procedure, why not use this definition using named let

(define (fact n)
  (let inner ((counter 1) (result 1))
    (if (> counter n)
        result
        (inner (+ counter 1) (* result counter)))))

Since the state of the process can be determined with just 2 variables, it will not use that much memory.

for example (fact 6) is computed like this

(inner 1 1)
(inner 2 1)
(inner 3 2)
(inner 4 6)
(inner 5 24)
(inner 6 120)
(inner 7 720)
720

Here is the letrec version of the same procedure:

(define (fact n)
  (letrec ((inner
            (lambda (counter result)
              (if (> counter n)
                  result
                  (inner (+ counter 1) (* result counter))))))
    (inner 1 1)))
like image 102
Rajesh Bhat Avatar answered Oct 04 '22 02:10

Rajesh Bhat


One thing you may be missing is that in Scheme there is no such thing as a "statement". Everything is an expression and things you might consider statements also return a value. This applies to if, which is typically used to return a value (e.g., (if (tea-drinker?) 'tea 'coffee). Unlike C++, most uses of conditionals are not going to be for mutating a variable or printing values. This reduces the need for having multiple expressions in an if clause.

However, as Ross and Rajesh have pointed out, you can use cond (recommended) or use begins in your if clauses. Note that if you have many side effecting computations in a conditional, you might not be using Scheme idiomatically.

like image 24
Asumu Takikawa Avatar answered Oct 04 '22 01:10

Asumu Takikawa


@RajeshBhat gave a good example of using begin with an if statement.

another solution is the cond form

(let ([arg1 0] [arg2 1])
  (cond
    [(< arg1 0) (display "negative!")]
    [(> arg1 arg2) (display arg1) (newline) (display "cool")]
    [else (display arg2) (newline) (display "not cool")]))

Each line in the cond form has an implicit begin which you can actually see if you look at the implementation of the cond.

(link is to the Chez Scheme documentation, might (read: probably) not be same implementation you are using as it is proprietary, though Petite Chez is free (no compiler in petite version))

http://scheme.com/tspl4/syntax.html#./syntax:s39

Edit: Important note about begin forms and therefore all expressions that have implicit begin's.

the following code

(+ 2 (begin 3 4 5))

evaluates to 7. This is because the return value of a begin form is its last expression. This is just something to keep in mind when using begins. However, using side-effects and things like displays will work just fine in the positions where the 3 and 4 are.

like image 29
Ross Larson Avatar answered Oct 04 '22 01:10

Ross Larson


If you feel restricted by Scheme's syntax, you can always change the syntax by defining a macro. A macro is like a lambda, except it generates code at compile-time (like a C++ template) and its arguments don't get evaluated before the macro is invoked.

You can easily make a macro to let you use the syntax that normally means procedure-application, like (arg1 "cool"), to mean "display everything inside the parentheses with a newline after each item". (It'll mean that only inside the macro, of course.) Like this:

(define-syntax print-if
  (syntax-rules ()
    [(_ c (true-print ...) (false-print ...))
      (if c
          (display-with-newlines true-print ...)
          (display-with-newlines false-print ...))]))

(define-syntax display-with-newlines
  (syntax-rules ()
    [(_ e)
      (begin (display e) (newline))]
    [(_ e0 e* ...)
      (begin (display-with-newlines e0) (display-with-newlines e* ...)) ]))

(let ([arg1 0] [arg2 1])
  (print-if (> arg1 arg2)
            (arg1 "cool")
            (arg2 "not cool")))

Output:

1
not cool

Don't worry if you don't understand how the macro definitions work right now. If you're just trying out Scheme after mastering C++, no doubt you're experiencing a lot of frustration. You should have a wee glimpse of the kind of power and flexibility Scheme really has.

A big difference between Scheme macros and C++ templates is that in a macro, the entire Scheme language is available to you. A macro tells, using Scheme, how to transform an s-expr into Scheme code, in any completely arbitrary way that you like. The compiler then compiles the Scheme code output by the macro. Since Scheme programs are themselves s-exprs, there are essentially no restrictions (other than lexical scoping and needing to enclose everything in parentheses).

And don't let anyone discourage you from using side-effects if you want to. The glory of Scheme is that you can do whatever you want.

like image 34
Ben Kovitz Avatar answered Oct 04 '22 01:10

Ben Kovitz