Community
SCI Programming => SCI Syntax Help => Topic started by: gumby on January 18, 2011, 08:15:20 AM
-
Any ideas how to implement something like this? I've checked the SCI Studio help file, but came up with nothing.
So instead of code like this (which I had to implement a temporary variable for holding the result of the first if)
(var tempResult)
(if (<condition>)
= tempResult <true>
) else (
= tempResult <false>
)
(if (== TRUE tempResult)
Print("Hello")
)
I'd like to do something like this: (the '?' and ':' are one of the ways I've seen other languages handle this)
(if (== TRUE (<condition> ? <true> : <false>))
Print("Hello")
)
-
I've never written any SCI code, but from what I've deduced regarding the original language, I doubt that such syntax existed. One reason for this is that it has an expression as the first item after the opening ( character. My understanding is that the first item would have been one of: keyword, operator, kernel function, procedure or an object. An expression that resolves to a boolean does not align with this. I guess what you could do though is define a reusable public procedure that gives you something like this behaviour.
-
There's the 'and' and 'not' characters that should work. I also recall something with "&&" and "|" that I've used in the past.
-
Err why don't you just do this?
(if (<condition>)
Print("Hello");
)
Or am I misunderstanding something?
-
My problem stems from porting code (programatically) that supports inline if's to SCI. A more reasonable example is:
(if ( > 5 ( a > 10 ? b : c ) )
...
)
So, it's mostly a problem of 'nested' if's. Some of the source code uses multiple inline-if's in the same statement, which aggravates the problem.
I would attempt a public procedure that could take care of the in-lines, but I don't think I can make it work when it comes to evaluation time - SCI doesn't seem to have an 'eval()' function (or similar).
My fallback is to re-write the if's to remove the nesting, like this:
(var temp)
(if (a > 10)
= temp b
) else (
= temp c
)
(if (> 5 temp)
...
)
-
I don't think it would need an eval() function. The evaluation of the condition would happen before the procedure is called. So in effect what you get is a TRUE or FALSE being passed to the procedure as the first parameter. I am making an assumption that boolean parameters are possible. Likewise the second and third parameters would be evaluated before passing their results to the procedure. The code in the procedure would be very trivial. All the hard word of the evaluation would be done prior to the procedure being called.
Thinking about it, the "if" keyword is almost what you need.
(if (<condition>) (<first-value>) else (<second-value>))
All the procedure would be doing is turning that into a short cut of:
(proc (<condition>) (<first-value>) (<second-value>))
The big difference though would be that the procedure returns the value it picks. I doubt that the if keyword returns a value (but then again I don't know, so perhaps that is worth testing out. It would be weird and cryptic if it does return a value though).
-
The more I think about it, the more I am wondering whether using the "if" keyword as is might not be such a silly idea:
(if (<condition>) (<first-value>) else (<second-value>))
What if it does return a value? Now that I think it through, it seems to make sense that most things have a value. Whether it makes sense or not is the point I guess.
The real question though is whether the compiler will let you put an "if" into this context, e.g. the compiler would have to allow this kind of code:
(= someVar (if (<condition>) (<first-value>) else (<second-value>)))
-
Yep, tried that and the compiler wouldn't buy it. It seems that an 'if' statement cannot result in just a 'primitive' (the <first-value> or <second-value>). It makes sense to me syntactically as well. I guess this means that an 'if' statement has no return value.
Which brings us around full-circle to your suggestion, Lance. I suppose I need a procedure that is an expression evaluator that returns a value (an 'if'/'then'/'else' replacement procedure).
I'm not up for building that (I think there are only a dozen or so in-line in references in the source code), I'll just bite the bullet and implement temporary holding variables instead.
-
I don't think it would need an eval() function. The evaluation of the condition would happen before the procedure is called. So in effect what you get is a TRUE or FALSE being passed to the procedure as the first parameter. I am making an assumption that boolean parameters are possible. Likewise the second and third parameters would be evaluated before passing their results to the procedure. The code in the procedure would be very trivial. All the hard word of the evaluation would be done prior to the procedure being called.
Thinking about it, the "if" keyword is almost what you need.
(if (<condition>) (<first-value>) else (<second-value>))
All the procedure would be doing is turning that into a short cut of:
(proc (<condition>) (<first-value>) (<second-value>))
The big difference though would be that the procedure returns the value it picks. I doubt that the if keyword returns a value (but then again I don't know, so perhaps that is worth testing out. It would be weird and cryptic if it does return a value though).
I missed this post... The reason I think I would need an eval() is that I'd like the procedure to be generic (accepting any sort of conditional statements) - returning the result would probably work just fine ('then' or 'else'), but I'd need some way to parse the conditional statement & evaluate it.
-
But I think that would be the beauty of it. You wouldn't need to pass in the condition. The condition is essentially self evaluating. e.g.
(proc (> var 5) (+ temp 7) (- bob 2))
The procedure doesn't see the condition expression or the calculation expressions. It sees the result. For example, if var is greater than 5 then the first argument to the procedure is a value of true. The condition expression could be as complex as you want it to be, including nested ands and ors and all that sort of thing. The procedure only ever sees a value of true or false for that first parameter. You would be using the power of the language to perfom the condition evaluation.
-
Keep in mind that is slightly different than an if/else, because in your case both expressions are always evaluated. (However in the example you gave it wouldn't matter, because neither expression modifies any state).
-
Brilliant Lance! It works perfectly. Here is a full working example:
(procedure public (iif pTrue pFalse pCondition)
(if (pCondition)
return pTrue
)(else
return pFalse
)
)
...
(if (== "blue" iif("blue" "green" > 1 2))
Print("It's blue")
)(else
Print("It's green")
)
The procedure accepts any conditional expression (at least on the surface). It will evaluate it and return either the true part (passed in with the 1st param) or the false part (passed in with the 2nd). The only hitch was I needed to put the true & false parameters first, so that the final parameter (the condition) would gobble up all the rest of the supplied values in the procedure call.
In the above example, the expression evaluates to false, so the value returned is "green", and we get the message "It's green".
We've already got a built-in expression evaluator! When the expression is passed into the procedure below, it's evaluated.
(procedure public (eval pExpression)
return pExpression
)
...
FormatPrint("%d" eval(+ 1 2)) // Will print '3'
I never would have thought that an approach like this would have worked. Thank you so much for the push in the right direction.
-
We've already got a built-in expression evaluator! When the expression is passed into the procedure below, it's evaluated.
(procedure public (eval pExpression)
return pExpression
)
...
FormatPrint("%d" eval(+ 1 2)) // Will print '3'
Actually, it's evaluated before its passed into the function. All that's doing is evaluating it to 3, then passing 3 to eval, which just returns it.
The same thing is happening with your iif procedure. iif doesn't receive the expression (> 1 2), it just receives the result of it.
I've looked at the SCIStudio compiler, and I wrote the SCICompanion compiler, so I'm sure of it :-).
That being said, it certainly seems like it would be possible to modify the compiler to allow for something like this (i.e. passing lambda functions to procedures).
-
I agree with troflip. The eval procedure is not required. The same thing would work if you did this:
FormatPrint("%d" (+ 1 2)) // Will print '3'
In the above example, it is actually the + that acts as a procedure. The 1 and 2 are in effect passed to it and it adds them together.
I'm surprised that you had to put the true and false parameters first. There should be no reason I can see why this would be required. What happens if you wrap the condition in () characters as in the following?
iif((> 1 2) "blue" "green")
Maybe the problem is that without the () the compiler is assuming that it is wrapped in () when it appears at the end of the parameter list. Maybe it can't assume that if the condition appears at the start of the parameter list, unless it is wrapped in () as in the above example. Yeah, thinking it through, if you were to write this:
iif(> 1 2 "blue" "green")
then the compiler would probably think that the 1, 2, "blue" and "green" are all parameters for the > operator.
-
Keep in mind that is slightly different than an if/else, because in your case both expressions are always evaluated. (However in the example you gave it wouldn't matter, because neither expression modifies any state).
Yes, this is a good point. It will always evaluate both, which might have side effects if the expression alters something in the process of evaluating the value. I guess there is extra work being done needlessly as well.
-
I think I made a mistake in my testing. I came to same conclusion (this morning) that the order of parameters is unimportant. The expression would be evaluated before passing it to the procedure. I'll test this tonight, but I'm nearly sure the order should make no difference. I don't see why I had such a problem with understanding this. You can do similar things in other languages (providing an expression for a parameter). Maybe it's because I'm still struggling with infix vs. prefix syntax & the lack of commas between procedure arguments?
You are both right, that eval() procedure is downright silly... where did I put my dunce cap?
Thanks again for the help, guys...
-
That being said, it certainly seems like it would be possible to modify the compiler to allow for something like this (i.e. passing lambda functions to procedures).
This reminds me of what has been happening with the Java VM. Languages such as Clojure and Scala compile to the JVM, as do many others. Having closures and passing functions as objects is where things get really powerful. I wonder how far a compiler could go with the SCI VM?
-
I've confirmed that parameter order does not matter (which makes perfect sense).
For those interested, here is the final code that I can up with - just with the parameters in a different order :)
(procedure public (iif pCondition pTrue pFalse)
(if (pCondition)
return pTrue
)(else
return pFalse
)
)
-
are you going to put something about it in the Wiki?
-
Done. http://www.sierrahelp.com/SCI/Wiki/index.php?title=Inline_If_Statements
-
Our Wiki is starting to flesh out nicely.
-
The real question though is whether the compiler will let you put an "if" into this context, e.g. the compiler would have to allow this kind of code:
(= someVar (if (<condition>) (<first-value>) else (<second-value>)))
I recently revisited this inline-if issue. The syntax suggested above is perfectly valid, it's just that Companion won't allow it. This does work in Studio.