Inverted syntax: Difference between revisions

From Rosetta Code
Content added Content deleted
Line 68: Line 68:
`(progn ,@(mapcar #'unrev-syntax forms)))</lang>
`(progn ,@(mapcar #'unrev-syntax forms)))</lang>


Test run:
Interactive test run:


<pre>$ clisp -q -i reverse.lisp
<pre>$ clisp -q -i reverse.lisp
Line 83: Line 83:
T
T
</pre>
</pre>

Now here is a slightly more complicated version which more closely conforms to the idea given in this task. The operator is assumed to be the second-last element of a form. The last element of the form is the first argument, and the forms prior to the operator are the remaining arguments (in reverse order). These rules are recursively applied to each of the arguments, but not to the operator. A two element form is assumed to be (argument operator), and is rewritten to
(operator argument*) where argument* is the result of applying the unreversal to the argument:

<lang lisp>(eval-when (:compile-toplevel :load-toplevel :execute)
(defun unrev-syntax (form)
(cond
((atom form) form) ;; atom: leave alone
((null (cdr form)) form) ;; one-element form, leave alone
((null (cddr form)) ;; two-element form, swap
(destructuring-bind (arg oper) form
`(,oper ,(unrev-syntax arg))))
(t ;; two or more args, swap and reverse whole thing
(destructuring-bind (arg1 oper &rest args) (reverse form)
`(,oper ,(unrev-syntax arg1) ,@(mapcar #'unrev-syntax args)))))))

(defmacro rprogn (&body forms)
`(progn ,@(mapcar #'unrev-syntax forms)))</lang>

<pre>[1]> (rprogn ((1 + 2) * (3 + 4)))
21
[2]> (rprogn (("not equal" print) ("equal" print) if (1 = 2)))

"not equal"
"not equal"
[3]> (rprogn (("not equal" print) ("equal" print) if (1 = 1)))

"equal"
"equal"
[4]> (macroexpand '(rprogn (("not equal" print) ("equal" print) if (1 = 1))))
(PROGN (IF (= 1 1) (PRINT "equal") (PRINT "not equal"))) ;
T
[5]> (macroexpand '(rprogn ((1 + 2) * (3 + 4))))
(PROGN (* (+ 4 3) (+ 2 1))) ;
T</pre>


=={{header|Icon}} and {{header|Unicon}}==
=={{header|Icon}} and {{header|Unicon}}==

Revision as of 20:54, 20 September 2011

Task
Inverted syntax
You are encouraged to solve this task according to the task description, using any language you may know.

Inverted syntax with conditional expressions

In traditional syntax conditional expressions are usually shown before the action within a statement or code block:

<lang pseudocode> IF raining=true THEN needumbrella=true </lang>

In inverted syntax, the action is listed before the conditional expression in the statement or code block:

<lang pseudocode> needumbrella=true IF raining=true </lang>

Inverted syntax with assignment

In traditional syntax, assignments are usually expressed with the variable appearing before the expression:

<lang pseudocode> a = 6</lang>

In inverted syntax, the expression appears before the variable: <lang pseudocode> 6 = a</lang>

Task

The task is to demonstrate support for inverted syntax forms within the language by showing both the traditional and inverted forms.

CoffeeScript

CoffeeScript allows loop constructs and conditionals to be written in a suffix manner. Loop constructs evaluate to an array containing the result of each iteration; conditionals evaluates either the true-case expression or the false-case one.

<lang coffeescript>alert "hello" if true alert "hello again" unless false # the same as the above; unless is a negated if.

idx = 0 arr = (++idx while idx < 10) # arr is [1,2,3,4,5,6,7,8,9,10]

idx = 0 arr = (++idx until idx is 10) # same as above; until is an inverted while.</lang>

Go

Go has one special form that is similar to an assignment with a trailing condition. The syntax for getting a value from a map looks like this: <lang go>v = m[k]</lang> where m is a map, k is a key, and v is the value returned. If the value is not in the map, the zero value for the type is returned.

Optionally, you can use the form, <lang go>v, ok = m[k]</lang> and ok is boolean that tells if the item was in the map or not.

Setting a value in a map also uses assignment syntax: <lang go>m[k] = v</lang> Now for the trailing condition: <lang go>m[k] = v, ok</lang> Here, ok can be any expression that evaluates to a bool. The value will be set in the map if ok is true. If ok is false, any value stored in the map under that key will be deleted from the map.

Common Lisp

Lisp has a PROGN macro for evaluating a bunch of forms, such that the value(s) of the last one is yielded as the result of the PROGN. We can create a reversed analog of PROGN, inside which, we must write the syntax backwards: arguments first, then the operator. Furthermore, this rule is recursively applied to expressions.

Note: unfortunately this is completely naive. To do this 100% right, we need a code walker, which is more complicated. However, code walkers are used in practice for hairy language transformation jobs, just not commonly so in daily Lisp programming. A code walker would let us imlement a more smarter version which would apply the transformation to forms which are evaluated, and not things like literal data. As it is, our macro also transforms literal data, making it impossible, for instance, to use the quote shorthand 'FORM. This stands for (QUOTE FORM) and of course, the macro will treat it as reversed syntax, transforming it to (FORM QUOTE). We could hack in a special case which recognized QUOTE, but then we do not know whether or not (QUOTE FORM) is in a context where it is being evaluated. That is why we need the code walker. It's best to use someone's well-tested, portable code-walker, since they are not trivial to write, and they have some implementation-specific parts (such as recognition of compiler-specific forms that come out of system macros or perhaps out of user-written nonportable code).


<lang lisp>(eval-when (:compile-toplevel :load-toplevel :execute)

 (defun unrev-syntax (form)
   (cond
     ((atom form) form)
     ((null (cddr form)) form)
     (t (destructuring-bind (oper &rest args) (reverse form)
          `(,oper ,@(mapcar #'unrev-syntax args)))))))

(defmacro rprogn (&body forms)

 `(progn ,@(mapcar #'unrev-syntax forms)))</lang>

Interactive test run:

$ clisp -q -i reverse.lisp
;; Loading file reverse.lisp ...
;; Loaded file reverse.lisp
[1]> (rprogn ((1 2 +) (3 4 +) *))
21
[2]> (rprogn (("not greater" print) ("greater" print) (1 2 >) if))

"greater"
"greater"
[3]> (macroexpand '(rprogn (("not greater" print) ("greater" print) (1 2 >) if)))
(PROGN (IF (> 2 1) (PRINT "greater") (PRINT "not greater"))) ;
T

Now here is a slightly more complicated version which more closely conforms to the idea given in this task. The operator is assumed to be the second-last element of a form. The last element of the form is the first argument, and the forms prior to the operator are the remaining arguments (in reverse order). These rules are recursively applied to each of the arguments, but not to the operator. A two element form is assumed to be (argument operator), and is rewritten to (operator argument*) where argument* is the result of applying the unreversal to the argument:

<lang lisp>(eval-when (:compile-toplevel :load-toplevel :execute)

 (defun unrev-syntax (form)
   (cond
     ((atom form) form) ;; atom: leave alone
     ((null (cdr form)) form) ;; one-element form, leave alone
     ((null (cddr form)) ;; two-element form, swap
      (destructuring-bind (arg oper) form
        `(,oper ,(unrev-syntax arg))))
     (t                  ;; two or more args, swap and reverse whole thing
      (destructuring-bind (arg1 oper &rest args) (reverse form)
       `(,oper ,(unrev-syntax arg1) ,@(mapcar #'unrev-syntax args)))))))

(defmacro rprogn (&body forms)

 `(progn ,@(mapcar #'unrev-syntax forms)))</lang>
[1]> (rprogn ((1 + 2) * (3 + 4)))
21
[2]> (rprogn (("not equal" print) ("equal" print) if (1 = 2)))

"not equal"
"not equal"
[3]> (rprogn (("not equal" print) ("equal" print) if (1 = 1)))

"equal"
"equal"
[4]> (macroexpand '(rprogn (("not equal" print) ("equal" print) if (1 = 1))))
(PROGN (IF (= 1 1) (PRINT "equal") (PRINT "not equal"))) ;
T
[5]> (macroexpand '(rprogn ((1 + 2) * (3 + 4))))
(PROGN (* (+ 4 3) (+ 2 1))) ;
T

Icon and Unicon

Icon and Unicon can use expression conjunctions that select different sub-expression results to create this effect. <lang Icon>procedure main() raining := TRUE := 1 # there is no true/false null/non-null will do if \raining then needumbrella := TRUE # normal needumbrella := 1(TRUE, \raining) # inverted (choose sub-expression 1) end</lang>

J

J tries to minimize syntax, and control structures. That said, they are present.

For control structures, "traditional conditional structures" are traditional (control structures implemented using keywords such as if. are not inverted). But J offers some alternatives which are inverted (operations such as ^:) or both (operations such as * (multiplication) can be used as inverted conditional structures or as traditional conditional structures, depending on whether you place the boolean test on the left or the right side). See Conditional_Structures/J for some examples.

Note also that simple, regular iteration without control structures is fundamental to the language (and turns data selection operations, including indexing, into conditional structures). But no special syntax is present for these cases so it can be neither traditional nor inverted.

m4

We extend our language with a new macro, thenif, to invert the arguments to the builtin macro, ifelse.

<lang m4>define(`thenif', `ifelse($2, $3, `$1')')dnl dnl ifelse(eval(23 > 5), 1, 23 is greater than 5) ifelse(eval(23 > 5), 0, math is broken) thenif(23 is greater than 5, eval(23 > 5), 1) thenif(math is broken, eval(23 > 5), 0)</lang>

This example outputs these four lines. Math was not broken, so two lines are empty.

23 is greater than 5

23 is greater than 5

PARI/GP

Works with: PARI/GP version version 2.4.2 and above

GP does not include a syntax-inverted if, but that can be defined using closures. <lang parigp>fi(f, condition)=if(condition,f());

if(raining, print("Umbrella needed")) fi(->print("Umbrella needed"), raining)</lang>

Perl

<lang perl>if ($guess == 6) { print "Wow! Lucky Guess!"; }; # Traditional syntax print 'Wow! Lucky Guess!' if $guess == 6; # Inverted syntax (note missing braces and parens) unless ($guess == 6) { print "Sorry, your guess was wrong!"; } # Traditional syntax print 'Huh! You Guessed Wrong!' unless $guess == 6; # Inverted syntax</lang>

Inverted syntax can also be used with the ternary operator. However this may produce different results to the traditional syntax form because when inverted syntax is used, we are effectively making an assignment to a ternary expression. so in the following example code, instead of the assignment being made to variable a (as it is in the traditional syntax form), the inverted syntax form will cause assignment to be made to either b or c, depending on value of the ok variable:

<lang perl># Note that the results obtained by the inverted syntax form

  1. may produce differing results from the traditional syntax form

$a = $ok ? $b : $c; # Traditional syntax ($ok ? $b : $c) = $a; # Inverted syntax</lang>

We can also emulate inverted syntax for scalar assignment by creating a function as follows:

<lang perl>sub assign { $_[1] = $_[0] } $a = $b; # Traditional syntax assign $b, $a; # Inverted syntax</lang>

Inverted list assignment is not possible because it prevents arrays from flattening.

Perl 6

Like all Perls, Perl 6 has statement modifiers: <lang perl6>if $guess == 6 { say "Wow! Lucky Guess!" } # Traditional say 'Wow! Lucky Guess!' if $guess == 6; # Inverted unless $guess == 6 { say "Huh! You Guessed Rong!" } # Traditional say 'Huh! You Guessed Rong!' unless $guess == 6; # Inverted</lang>

Perl also inverts the syntax of loops: <lang perl6>while $i { --$i } --$i while $i;

until $x > 10 { $x++ } $x++ until $x > 10;

for 1..10 { .say if $_ %% 2 } .say if $_ %% 2 for 1..10; # list comprehension</lang>

Perl 6 has a system of metaoperators that modify the characteristics of normal operators. Among these is the R metaoperator, which is able to reverse the arguments of most infix operators (including user-defined ones). So a reversed assignment is easy to write: <lang perl6>42 R= $_; say $_; # prints 42</lang> Since, much like list operators, assignment loosens the precedence of the following expression to allow comma lists, reverse assignment of a list requires parens where the normal assignment would not: <lang perl6>my @a = 1,2,3; (1,2,3) R= my @a;</lang> However, generally in that case you'd use a feed operator anyway, which is like an object pipe, but unlike Unix pipes works in either direction: <lang perl6>my @a <== 1,2,3; 1,2,3 ==> my @a;</lang> We think this is much more readable than a reversed assignment.

One other interesting inversion is the ability to put the conditional of a repeat loop at either end, with identical test-after semantics: <lang perl6>repeat {

   $_ = prompt "Gimme a number: ";

} until /^\d+$/;

repeat until /^\d+$/ {

   $_ = prompt "Gimme a number: ";

}</lang> This might seem relatively useless, but it allows a variable to be declared in the conditional that isn't actually set until the loop body: <lang perl6>repeat until my $answer ~~ 42 {

   $answer = prompt "Gimme an answer: ";

}</lang> This would require a prior declaration (and two extra semicolons, horrors) if written in the non-inverted form with the conditional at the bottom: <lang perl6>my $answer; repeat {

   $answer = prompt "Gimme an answer: ";

} until $answer ~~ 42;</lang> You can't just put the my on the $answer in the block because the conditional is outside the scope of the block, and would not see the declaration.

PicoLisp

We define a read macro for reverted syntax <lang PicoLisp>(de rv Prg

  (append (last Prg) (head -1 Prg)) )</lang>

Test:

(de needUmbrella (Raining)
   `(rv                                # Inverted syntax
      (on *NeedUmbrella)
      (println 'Need 'an 'umbrella)
      (when Raining) ) )

(de keepUmbrella (Raining)
   `(rv                                # Inverted syntax
      (on *KeepUmbrella)
      (println 'Still 'need 'an 'umbrella)
      (while Raining) ) )

Output:

: (pp 'needUmbrella)
(de needUmbrella (Raining)
   (when Raining                       # Traditional syntax
      (on *NeedUmbrella)
      (println 'Need 'an 'umbrella) ) )

: (pp 'keepUmbrella)
(de keepUmbrella (Raining)
   (while Raining                      # Traditional syntax
      (on *KeepUmbrella)
      (println 'Still 'need 'an 'umbrella) ) )

Python

<lang python>x = truevalue if condition else falsevalue</lang>


Qi

<lang qi> (define set-needumbrella

 Raining -> (set needumbrella true) where (= true Raining)
 Raining -> (set needumbrella false) where (= false Raining))

(define set-needumbrella

 Raining -> (if (= true Raining)
                (set needumbrella true)
                (set needumbrella false)))


Alternatives:

(define set-needumbrella

 Raining -> (set needumbrella true) where Raining
 Raining -> (set needumbrella false))

(define set-needumbrella

 Raining -> (if Raining
                (set needumbrella true)
                (set needumbrella false)))

(define set-needumbrella

 true  -> (set needumbrella true)
 false -> (set needumbrella false))

(define set-needumbrella

 A -> (set needumbrella A))

</lang>

R

This can be done with a simple function.

<lang R>do.if <- function(expr, cond) if(cond) expr</lang>

Because R evaluates function arguments lazily, "expr" is never evaluated unless "cond" evaluates to true.

<lang R>do.if(print("Wow! Lucky Guess!"), guess==6)</lang>

If you do not want to state "do.if" first, you can define an infix operator (any function whose name is bracketed in percent signs is treated as an infix operator), however custom infix operators have higher precedence than comparisons, so will usually require putting parentheses around the test.

<lang r>`%if%` <- function(expr, cond) if(cond) expr

print("Wow! Lucky Guess!") %if% (guess==6)</lang>

Ruby

Ruby takes, from Perl, the idea of a statement modifier. This looks like statement if condition and appends a condition to some statement. This example shows how to invert if, unless, while and until. These always check the condition before running the statement.

<lang ruby># Raise ArgumentError if n is negative. if n < 0 then raise ArgumentError, "negative n" end raise ArgumentError, "negative n" if n < 0

  1. Exit 1 unless we can call Process.fork.

unless Process.respond_to? :fork then exit 1 end exit 1 unless Process.respond_to? :fork

  1. Empty an array, printing each element.

while ary.length > 0 do puts ary.shift end puts ary.shift while ary.length > 0

  1. Another way to empty an array, printing each element.

until ary.empty? do puts ary.shift end puts ary.shift until ary.empty?</lang>

One can also modify a compound statement, as in (warn "cannot fork"; exit 1) unless Process.respond_to? :fork.

Beware: The forms begin ... end while ... and begin ... end until ... have a different meaning to Ruby. These forms check the condition after each iteration, so they run the loop at least once. Loops/Do-while#Ruby has more information.

Tcl

Copied verbatim from do.tcl, a part of tcllib's control package. <lang tcl>

  1. do.tcl --
  2. Tcl implementation of a "do ... while|until" loop.
  3. Originally written for the "Texas Tcl Shootout" programming contest
  4. at the 2000 Tcl Conference in Austin/Texas.
  5. Copyright (c) 2001 by Reinhard Max <Reinhard.Max@gmx.de>
  6. See the file "license.terms" for information on usage and redistribution
  7. of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  8. RCS: @(#) $Id: do.tcl,v 1.6 2004/01/15 06:36:12 andreas_kupries Exp $

namespace eval ::control {

   proc do {body args} {

# # Implements a "do body while|until test" loop # # It is almost as fast as builtin "while" command for loops with # more than just a few iterations. #

set len [llength $args] if {$len !=2 && $len != 0} { set proc [namespace current]::[lindex [info level 0] 0] return -code error "wrong # args: should be \"$proc body\" or \"$proc body \[until|while\] test\"" } set test 0 foreach {whileOrUntil test} $args { switch -exact -- $whileOrUntil { "while" {} "until" { set test !($test) } default { return -code error \ "bad option \"$whileOrUntil\": must be until, or while" } } break }

# the first invocation of the body set code [catch { uplevel 1 $body } result]

# decide what to do upon the return code: # # 0 - the body executed successfully # 1 - the body raised an error # 2 - the body invoked [return] # 3 - the body invoked [break] # 4 - the body invoked [continue] # everything else - return and pass on the results # switch -exact -- $code { 0 {} 1 { return -errorinfo [ErrorInfoAsCaller uplevel do] \ -errorcode $::errorCode -code error $result } 3 { # FRINK: nocheck return } 4 {} default { return -code $code $result } } # the rest of the loop set code [catch {uplevel 1 [list while $test $body]} result] if {$code == 1} { return -errorinfo [ErrorInfoAsCaller while do] \ -errorcode $::errorCode -code error $result } return -code $code $result

   }

}

  1. usage:

package require control control::do {set i 0; puts "hello world"; incr i} until {$i > 0} </lang>

A more radical and probably ill-advised approach is to use the above and modify the default tcl unknown procedure along these lines:

<lang tcl> rename unknown __unknown proc unknown {args} {

  if {3 == [llength $args]} {
     package require control
     return [control::do {*}$args]
  } else {
     return [__unknown {*}$args]
  }

}

  1. usage

% {set i 0; puts "hello world"; incr i} until {$i > 0} hello world </lang>