text:
Extend your language
You are encouraged to solve this task according to the task description, using any language you may know.
These are examples of control structures. You may also be interested in:
Some programming languages allow you to extend the language. While this can be done to a certain degree in most languages (e.g. by using macros), other languages go much further. Most notably in the Forth and Lisp families, programming per se is done by extending the language without any formal distinction between built-in and user-defined elements.
If your language supports it, show how to introduce a new flow control mechanism. A practical and useful example is a four-way branch:
Occasionally, code must be written that depends on two conditions, resulting in up to four branches (depending on whether both, only the first, only the second, or none of the conditions are "true"). In a C-like language this could look like the following:
if (condition1isTrue) { if (condition2isTrue) bothConditionsAreTrue(); else firstConditionIsTrue(); } else if (condition2isTrue) secondConditionIsTrue(); else noConditionIsTrue();
Besides being rather cluttered, the statement(s) for 'condition2isTrue' must be written down twice. If 'condition2isTrue' were a lengthy and involved expression, it would be quite unreadable, and the code generated by the compiler might be unnecessarily large.
This can be improved by introducing a new keyword if2. It is similar to if, but takes two conditional statements instead of one, and up to three 'else' statements. One proposal (in pseudo-C syntax) might be:
if2 (condition1isTrue) (condition2isTrue) bothConditionsAreTrue(); else1 firstConditionIsTrue(); else2 secondConditionIsTrue(); else noConditionIsTrue();
Pick the syntax which suits your language. The keywords 'else1' and 'else2' are just examples. The new conditional expression should look, nest and behave analogously to the language's built-in 'if' statement.
- 1 Ada
- 4 Clay
- 5 Clojure
- 7 Common Lisp
- 9 Delphi
- 11 EchoLisp
- 12 Factor
- 13 Forth
- 14 FreeBASIC
- 15 Haskell
- 16 Icon and Unicon
- 17 Inform 7
- 19 Kotlin
- 20 Lasso
- 21 Mathematica / Wolfram Language
- 22 Morfa
- 23 Nemerle
- 24 NewLISP
- 25 Nim
- 27 Perl
- 28 Perl 6
- 29 Phix
- 31 PicoLisp
- 32 PowerShell
- 33 Python
- 35 Racket
- 36 Retro
- 38 Ruby
- 39 Rust
- 40 Scala
- 41 Scheme
- 42 Seed7
- 43 Shen
- 44 Sidef
- 45 Tcl
- 47 UNIX Shell
- 48 Ursala
with Ada.Text_IO; use Ada.Text_IO;
procedure Test_If_2 is
type Two_Bool is range 0 .. 3;
function If_2(Cond_1, Cond_2: Boolean) return Two_Bool is
(Two_Bool(2*Boolean'Pos(Cond_1)) + Two_Bool(Boolean'Pos(Cond_2)));
for N in 10 .. 20 loop
Put(Integer'Image(N) & " is ");
case If_2(N mod 2 = 0, N mod 3 = 0) is
when 2#11# => Put_Line("divisible by both two and three.");
when 2#10# => Put_Line("divisible by two, but not by three.");
when 2#01# => Put_Line("divisible by three, but not by two.");
when 2#00# => Put_Line("neither divisible by two, nor by three.");
end case;
end loop;
end Test_If_2;
- Output:
10 is divisible by two, but not by three. 11 is neither divisible by two, nor by three. 12 is divisible by both two and three. 13 is neither divisible by two, nor by three. 14 is divisible by two, but not by three. 15 is divisible by three, but not by two. 16 is divisible by two, but not by three. 17 is neither divisible by two, nor by three. 18 is divisible by both two and three. 19 is neither divisible by two, nor by three. 20 is divisible by two, but not by three.
ALGOL 68[edit]
# operator to turn two boolean values into an integer - name inspired by the COBOL sample #
OP ALSO = ( BOOL a, b )INT: IF a AND b THEN 1 ELIF a THEN 2 ELIF b THEN 3 ELSE 4 FI;
# using the above operator, we can use the standard CASE construct to provide the #
# required construct, e.g.: #
BOOL a := TRUE, b := FALSE;
CASE a ALSO b
IN print( ( "both: a and b are TRUE", newline ) )
, print( ( "first: only a is TRUE", newline ) )
, print( ( "second: only b is TRUE", newline ) )
, print( ( "neither: a and b are FALSE", newline ) )
This task requires syntax different from the
if keyword in C. For example:
/* Four-way branch.
* if2 (firsttest, secondtest
* , bothtrue
* , firstrue
* , secondtrue
* , bothfalse
* )
#define if2(firsttest,secondtest,bothtrue,firsttrue,secondtrue,bothfalse)\
switch(((firsttest)?0:2)+((secondtest)?0:1)) {\
case 0: bothtrue; break;\
case 1: firsttrue; break;\
case 2: secondtrue; break;\
case 3: bothfalse; break;\
Example application:
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "if2.h"
int main(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; i++) {
char *arg= argv[i], *ep;
long lval = strtol(arg, &ep, 10); /* convert arg to long */
if2 (arg[0] == '\0', *ep == '\0'
, puts("empty string")
, puts("empty string")
, if2 (lval > 10, lval > 100
, printf("%s: a very big number\n", arg)
, printf("%s: a big number\n", arg)
, printf("%s: a very big number\n", arg)
, printf("%s: a number\n", arg)
, printf("%s: not a number\n", arg)
return 0;
Example invocation:
$ make exten && ./exten 3 33 333 3a b " " -2
cc exten.c -o exten
3: a number
33: a big number
333: a very big number
3a: not a number
b: not a number
: not a number
-2: a number
The following is probably easier to read, although
fi2 is funny looking however you slice it. On the other hand, this kind of macros are unquestionably in the "bad" category.
#include <stdio.h>
#define if2(a, b) switch(((a)) + ((b)) * 2) { case 3:
#define else00 break; case 0: /* both false */
#define else10 break; case 1: /* true, false */
#define else01 break; case 2: /* false, true */
#define else2 break; default: /* anything not metioned */
#define fi2 } /* stupid end bracket */
int main()
int i, j;
for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) {
printf("%d %d: ", i, j);
if2 (i == 1, j == 1)
else00 { /* <-- bracket is optional, flaw */,
if2 (i == 2, j == 2)
printf("\tis 22");
printf("\n"); /* flaw: this is part of if2! */
printf("\tnot 22\n");
return 0;
alias if2(cond1:Bool,
var res1 = cond1;
var res2 = cond2;
if (res1 and res2) return both;
if (res1) return first;
if (res2) return second;
return neither;
Clojure being a LISP has macros.
(defmacro if2 [[cond1 cond2] bothTrue firstTrue secondTrue else]
`(let [cond1# ~cond1
cond2# ~cond2]
(if cond1# (if cond2# ~bothTrue ~firstTrue)
(if cond2# ~secondTrue ~else))))
> (if2 [true true] 'bothTrue 'firstTrue 'secondTrue 'else) bothTrue > (if2 [false true] 'bothTrue 'firstTrue 'secondTrue 'else) secondTrue > (if2 [true false] 'bothTrue 'firstTrue 'secondTrue 'else) firstTrue > (if2 [false false] 'bothTrue 'firstTrue 'secondTrue 'else) else > (macroexpand '(if2 ['c1 'c2] 'bothTrue 'firstTrue 'secondTrue 'else)) (let* [cond2__1806__auto__ (quote c2)] (if (quote c1) (if cond2__1806__auto__ (quote bothTrue) (quote firstTrue)) (if cond2__1806__auto__ (quote secondTrue) (quote else))))
Cobol already has a multiple-if:
DISPLAY 'Both are true.'
DISPLAY 'Expression 1 is true.'
DISPLAY 'Expression 2 is true.'
DISPLAY 'Neither is true.'
(Of course, Cobol is also inherently non-extensible.)
Common Lisp[edit]
(defmacro if2 (cond1 cond2 both first second &rest neither)
(let ((res1 (gensym))
(res2 (gensym)))
`(let ((,res1 ,cond1)
(,res2 ,cond2))
(cond ((and ,res1 ,res2) ,both)
(,res1 ,first)
(,res2 ,second)
(t ,@neither)))))
Interactive tests to validate if2.
- Forms evaluate once
- Forms evaluate in left-to-right order
- Suppressed antecedents do not evaluate
[1]>(defmacro tr (form) `(progn (format t "form ~s evaluating~%" ',form) ,form)) TR [2]> (if2 (tr (< 1 2)) (tr (oddp 3)) (tr "both") (tr "first") (tr "second") (tr "neither")) form (< 1 2) evaluating form (ODDP 3) evaluating form "both" evaluating "both" [3]> (if2 (tr (< 1 2)) (tr (oddp 4)) (tr "both") (tr "first") (tr "second") (tr "neither")) form (< 1 2) evaluating form (ODDP 4) evaluating form "first" evaluating "first" [4]> (if2 (tr (< 2 1)) (tr (oddp 4)) (tr "both") (tr "first") (tr "second") (tr "neither")) form (< 2 1) evaluating form (ODDP 4) evaluating form "neither" evaluating "neither"
Proper nesting and hygiene: check by inspection of macro expansions.
- Axiom: standard language features LET and COND nest properly.
- The local variables introduced into the expansion by the generated LET are using unique uninterned symbols (obvious by #: notation) that cannot possibly occur in the code. Even if #:G2908 appears in code, two occurrences of that notation produce different symbol objects not EQ to each other, which just have the same name. Two occurrences of #:G2908 in the macro expansion are the same symbol, because they are just two insertions of the same object into the list structure.
- Function space hygiene is not a problem by fiat: Common Lisp programs which define their own functions called LET, COND invoke undefined behavior by the ANSI standard. Macros make liberal use of the standard operators in their expansions.
[1]> (macroexpand '(if2 c1 c2 b f s n1 n2 n3)) (LET ((#:G2907 C1) (#:G2908 C2)) (COND ((AND #:G2907 #:G2908) B) (#:G2907 F) (#:G2908 S) (T N1 N2 N3))) ; T [2]> (macroexpand '(if2 c1 c2 b f s n1 n2 n3)) (LET ((#:G2909 C1) (#:G2910 C2)) (COND ((AND #:G2909 #:G2910) B) (#:G2909 F) (#:G2910 S) (T N1 N2 N3))) ; T ;;; show that multiple gensyms are the same symbol using Lisp's ;;; circle notation which reveals shared substructures and cycles [3]> (setf *print-circle* t) T [4]> (macroexpand '(if2 c1 c2 b f s n1 n2 n3)) (LET ((#1=#:G2917 C1) (#2=#:G2918 C2)) (COND ((AND #1# #2#) B) (#1# F) (#2# S) (T N1 N2 N3))) ; T
D features lazy arguments, which can be used for this task.
void if2(T1, T2, T3, T4)(in bool c1, in bool c2,
lazy T1 first,
lazy T2 both,
lazy T3 second,
lazy T4 none) {
if (c1) {
if (c2)
} else {
if (c2)
void test(in bool a, in bool b) {
import std.stdio;
if2(a, b, writeln("first"),
void main() {
test(1 < 2, 3 > 4);
test(1 < 2, 1 < 2);
test(3 > 4, 3 > 4);
test(3 > 4, 1 < 2);
- Output:
first both none second
First example:
procedure Check(Condition1: Boolean; Condition2: Boolean)
if Condition1 = True then
if Condition2 = True then
if Condition2 = True then
Second example:
procedure Check(Condition1: Boolean; Condition2: Boolean)
if (Condition1 = True) and (Condition2 = True) then
else if Condition1 = True then
else if Condition2 = True then
else NoConditionIsTrue;
In both examples if Condition1 and/or Condition2 are Booleans you can omit the '= True' (not when for instance comparing Integers: a = 1)
E may be thought of as like JavaScript or Smalltalk; you are expected to define control flow in terms of closures. In fact, all built-in loops internally expand to closures. However, we do provide (experimentally) a syntax for making your user-defined control structures look more like builtins.
The feature is called "lambda-args", and it allows you to write
controlName (args...) someKeyword params... { ... code ... } [ someKeyword params... { ... code ... }]*.
The control structure is built up and then executed by chained method calls (similar to jQuery) starting from the controlName object, one for each {}, each of which takes a closure as a parameter. The first closure actually returns the parenthesized args evaluated and a closure for the first {}, which the args are in scope for; the closures for all following {} do not have the args in scope.
pragma.enable("lambda-args") # The feature is still experimental syntax
def makeIf2Control(evalFn, tf, ft, ff) {
return def if2Control {
to only1__control_0(tf) { return makeIf2Control(evalFn, tf, ft, ff) }
to only2__control_0(ft) { return makeIf2Control(evalFn, tf, ft, ff) }
to else__control_0 (ff) { return makeIf2Control(evalFn, tf, ft, ff) }
to run__control() {
def [[a :boolean, b :boolean], # Main parameters evaluated
tt # First block ("then" case)
] := evalFn()
return (
if (a) { if (b) {tt} else {tf} } \
else { if (b) {ft} else {ff} }
def if2 {
# The verb here is composed from the keyword before the brace, the number of
# parameters in the parentheses, and the number of parameters after the
# keyword.
to then__control_2_0(evalFn) {
# evalFn, when called, evaluates the expressions in parentheses, then
# returns a pair of those expressions and the first { block } as a
# closure.
return makeIf2Control(evalFn, fn {}, fn {}, fn {})
for a in [false,true] {
for b in [false,true] {
if2 (a, b) then {
} only1 {
println("a true")
} only2 {
println("b true")
} else {
The internal expansion of the "if2" block above is:
if2.then__control_2_0(fn {
[[a, b], fn {
}).only1__control_0(fn {
println("a true")
}).only2__control_0(fn {
println("b true")
}).else__control_0(fn {
define-syntax and define-syntax-rules are here to extend the language
(if2 cond1 cond2 both cond1-only cond2-only none) ;; new syntax
;; will expand to :
(if cond1
(if cond2 both cond1-only)
(if cond2 cond2-only none)))
→ #syntax:if2
(define (num-test n)
(if2 (positive? n) (exact? n)
"positive and exact"
"positive and inexact"
"negative and exact"
"negative and inexact"))
(num-test 3/4)
→ "positive and exact"
(num-test -666)
→ "negative and exact"
(num-test -666.42)
→ "negative and inexact"
(num-test PI)
→ "positive and inexact"
Not too hard, as long as you're not worried about choking to death on stack effects:
( scratchpad ) : 2ifte ( ..a ?0 ?1 quot0: ( ..a -- ..b ) quot1: ( ..a -- ..b ) quot2: ( ..a -- ..b ) quot3: ( ..a -- ..b ) -- ..b )
[ [ if ] curry curry ] 2bi@ if ; inline
( scratchpad ) 3 [ 0 > ] [ even? ] bi [ 0 ] [ 1 ] [ 2 ] [ 3 ] 2ifte .
Control structures in Forth are just IMMEDIATE words, which flags them to be run at compile time. POSTPONE invokes the compile-time semantics of words instead of executing them.
\ in this construct, either of the ELSE clauses may be omitted, just like IF-THEN.
: BOTH postpone IF postpone IF ; immediate
: ORELSE postpone THEN postpone ELSE postpone IF ; immediate
: NEITHER postpone THEN postpone THEN ; immediate
: fb ( n -- )
dup 5 mod 0= over 3 mod 0=
BOTH ." FizzBuzz "
ELSE ." Fizz "
ORELSE ." Buzz "
ELSE dup .
NEITHER drop ;
: fizzbuzz ( n -- ) 0 do i 1+ fb loop ;
' FB 1.05.0 Win64
#Macro If2(condition1, condition2)
#Define Else1 ElseIf CBool(condition1) Then
#Define Else2 ElseIf CBool(condition2) Then
If CBool(condition1) AndAlso CBool(condition2) Then
Sub test(a As Integer, b As Integer)
If2(a > 0, b > 0)
print "both positive"
print "first positive"
print "second positive"
print "neither positive"
End If
End Sub
Dim As Integer a, b
Print "a = 1, b = 1 => ";
test(1, 1)
Print "a = 1, b = 0 => ";
test(1, 0)
Print "a = 0, b = 1 => ";
test(0, 1)
Print "a = 0, b = 0 => ";
test(0, 0)
Print "Press any key to quit"
- Output:
a = 1, b = 1 => both positive a = 1, b = 0 => first positive a = 0, b = 1 => second positive a = 0, b = 0 => neither positive
Expressions in Haskell are not evaluated until they are needed, so ordinary functions can be control structures.
if2 :: Bool -> Bool -> a -> a -> a -> a -> a
if2 p1 p2 e12 e1 e2 e =
if p1 then
if p2 then e12 else e1
else if p2 then e2 else e
main = print $ if2 True False (error "TT") "TF" (error "FT") (error "FF")
Icon and Unicon[edit]
Icon, and Unicon, provide a means of programmatically adding new control regimes but not of extending the syntax for the same into a new control structure. Instead, a Programmer-Defined Control Operation (PDCO) may be defined and used. Here is an example:
procedure main(A)
if2 { (A[1] = A[2]), (A[3] = A[4]), # Use PDCO with all three else clauses
write("1: both true"),
write("1: only first true"),
write("1: only second true"),
write("1: neither true")
if2 { (A[1] = A[2]), (A[3] = A[4]), # Use same PDCO with only one else clause
write("2: both true"),
write("2: only first true"),
procedure if2(A) # The double-conditional PDCO
suspend if @A[1] then
if @A[2] then |@A[3] # Run-err if missing 'then' clause
else @\A[4] # (all else clauses are optional)
else if @A[2] then |@\A[5]
else |@\A[6]
and some sample runs:
->eyl 1 1 2 2 1: both true 2: both true ->eyl 1 1 2 3 1: only first true 2: only first true ->eyl 1 2 2 2 1: only second true ->eyl 1 2 3 4 1: neither true ->
The use of a PDCO does impose some restrictions over native control structures. The largest is that each clause in the PDCO is fully isolated from the others, so variables defined and used in one clause are not accessible in another (this includes, in this example, the two conditional clauses). Similarly, changes to procedure local variables made in any clause are not recorded outside the PDCO. So the use of PDCO is best viewed as a partial solution to this particular task.
Inform 7[edit]
Inform 7 has two syntaxes for flow control blocks. Unfortunately, the newer indentation-based syntax only works with the built-in flow control statements, but it's possible to define new flow control statements using the older begin...end syntax:
To if2 (c1 - condition) and-or (c2 - condition) begin -- end: (- switch (({c1})*2 + ({c2})) { 3: do -).
To else1 -- in if2: (- } until (1); 2: do { -).
To else2 -- in if2: (- } until (1); 1: do { -).
To else0 -- in if2: (- } until (1); 0: -).
Note that the "else0" part must be given, although "else1" and "else2" are optional. Demonstration:
Home is a room.
When play begins:
if2 (the player is in Home) and-or (the player is a person) begin;
say "both";
say "only 1";
say "only 2";
say "neither";
end if2.
Text substitution[edit]
To say if2 (c1 - condition) and-or (c2 - condition) -- beginning if2:
(- switch (({c1})*2 + ({c2})) { 3: -).
To say else1 -- continuing if2: (- 2: -).
To say else2 -- continuing if2: (- 1: -).
To say else0 -- continuing if2: (- 0: -).
To say end if2 -- ending if2: (- } -).
Home is a room.
When play begins:
say "[if2 the player is not in Home and-or the player is not a person]both[else1]only 1[else2]only 2[else0]neither[end if2]".
In general, J's adverbs (
1 :) and conjunctions (
2 :) allow the creation of fairly arbitrary control words.
J's grammar uses a valence concept - originally from chemistry, but also used in linguistics. Briefly: J's nouns have no "binding potential" but can satisfy the binding needs of verbs, adverbs and conjunctions. Meanwhile, J's verbs can bind 1 or 2 nouns and can only produce a noun result. Verbs must bind with a noun on their right, and may optionally bind with a noun on their left (if and only if a noun is available for left binding). J's adverbs have a tight binding on their left which must be satisfied (and can be satisfied by either a noun or a verb). J's conjunctions have a tight binding on their left and right, both of which can be satisfied by either a noun or a verb. Adverbs and conjunctions can produce any kind of result (noun, adverb, conjunction, or verb) and their result's bindings must also be grammatically satisfied (in other words, they are somewhat like macros of other high level languages, though of course the formal details are a bit different).
Also, when creating an explicit definition using the
: conjunction, the type of result is marked with a small integer indicating its binding potential: 0 (noun), 1 (adverb), 2 (conjunction), with higher values indicating various flavors of verbs (3 for the typical case).
Here, we extend our language by defining a conjunction
if2 which consumes two nouns and produces a verb:
if2=: 2 :0
'`b1 b2'=. n
m@.(b1 + 2 * b2) f.
Example use:
f0=: [: smoutput 'neither option: ' , ":
f1=: [: smoutput 'first option: ' , ":
f2=: [: smoutput 'second option: ' , ":
f3=: [: smoutput 'both options: ' , ":
isprime=: 1&p:
iseven=: 0 = 2&|
f0`f1`f2`f3 if2 (isprime`iseven)"0 i.5
second option: 0
neither option: 1
both options: 2
first option: 3
second option: 4
That said, note that a switch statement which combines the boolean conditions as a base 2 number might be more convenient.
Note also that J allows words to be defined with the semantic properties that would in TCL be accessed using
uplevel 1. However, these are often not useful in J in part because the natural approach to J programming has blocks be named (and referred to by name), and meaningful names are hard to come up with for these side-effect-based constructs but mostly because it's usually far more concise and clear to express the desired calculations directly.
(Also, most operations in J have built in data-driven looping (and, thus, conditional) capabilities - J automatically loops over all values in an array, and both data selection and multiplication can be used to handle conditional issues - so re-inventing that wheel rather quickly loses its luster.)
Kotlin does not have macros or the like but, using a combination of chained functions and lambdas, it's possible to create something which closely resembles a language extension:
// version 1.0.6
data class IfBoth(val cond1: Boolean, val cond2: Boolean) {
fun elseFirst(func: () -> Unit): IfBoth {
if (cond1 && !cond2) func()
return this
fun elseSecond(func: () -> Unit): IfBoth {
if (cond2 && !cond1) func()
return this
fun elseNeither(func: () -> Unit): IfBoth {
if (!cond1 && !cond2) func()
return this // in case it's called out of order
fun ifBoth(cond1: Boolean, cond2: Boolean, func: () -> Unit): IfBoth {
if (cond1 && cond2) func()
return IfBoth(cond1, cond2)
fun main(args: Array<String>) {
var a = 0
var b = 1
ifBoth (a == 1, b == 3) {
println("a = 1 and b = 3")
.elseFirst {
println("a = 1 and b <> 3")
.elseSecond {
println("a <> 1 and b = 3")
.elseNeither {
println("a <> 1 and b <> 3")
// It's also possible to omit any (or all) of the 'else' clauses or to call them out of order
a = 1
b = 0
ifBoth (a == 1, b == 3) {
println("a = 1 and b = 3")
.elseNeither {
println("a <> 1 and b <> 3")
.elseFirst {
println("a = 1 and b <> 3")
- Output:
a <> 1 and b <> 3 a = 1 and b <> 3
Lasso doesn't allow you to define new keywords for the parser, but it does allow you to achieve a similar effect using captures and givenblock as illustrated below.
// Create a type to handle the captures
define if2 => type {
data private a, private b
public oncreate(a,b) => {
.a = #a
.b = #b
handle => { thread_var_pop(.type)}
return givenblock()
public ifboth => .a && .b ? givenblock()
public else1 => .a && !.b ? givenblock()
public else2 => !.a && .b ? givenblock()
public else => !.a && !.b ? givenblock()
// Define methods to consider givenblocks
define ifboth => thread_var_get(::if2)->ifboth => givenblock
define else1 => thread_var_get(::if2)->else1 => givenblock
define else2 => thread_var_get(::if2)->else2 => givenblock
define else => thread_var_get(::if2)->else => givenblock
Example use:
if2(true,true) => {
ifboth => {
else1 => {
else2 => {
else => {
Mathematica / Wolfram Language[edit]
Mathematica is not precisely a Lisp, but it can easily construct macros by holding the arguments to a function:
If2[test1_, test2_, condBoth_, cond1_, cond2_, condNone_] := With[
{result1 = test1,
result2 = test2},
result1 && result2, condBoth,
result1, cond1,
result2, cond2,
True, condNone]];
SetAttributes[If2, HoldAll];
Example usage (note that the tests are evaluated only once per call):
x = 0;
If2[Mod[(++x), 2] == 0, Mod[x, 3] == 1, Print["Both: ", x], Print["First: ", x], Print["Second: ", x], Print["Neither: ", x]];
If2[Mod[(++x), 2] == 0, Mod[x, 3] == 1, Print["Both: ", x], Print["First: ", x], Print["Second: ", x], Print["Neither: ", x]];
If2[Mod[(++x), 2] == 0, Mod[x, 3] == 1, Print["Both: ", x], Print["First: ", x], Print["Second: ", x], Print["Neither: ", x]];
If2[Mod[(++x), 2] == 0, Mod[x, 3] == 1, Print["Both: ", x], Print["First: ", x], Print["Second: ", x], Print["Neither: ", x]];
- Output:
Second: 1 First: 2 Neither: 3 Both: 4
Morfa's operator defining and overloading can be employed to provide more natural syntax for expressing an if2 "statement".
import morfa.base;
// introduce 4 new operators to handle the if2 syntax
operator then { kind = infix, precedence = mul, associativity = right}
operator else1 { kind = infix, precedence = not, associativity = left }
operator else2 { kind = infix, precedence = not, associativity = left }
operator none { kind = infix, precedence = not, associativity = left }
// function which bounds the condition expression to the if2 "actions"
public func then(condition: IF2.Condition, actionHolder: IF2): void
// functions (bound to operators) used to "build" the if2 "statement"
public func else1(bothAction: func(): void, else1Action: func(): void): IF2
return IF2([IF2.Condition.both -> bothAction,
IF2.Condition.else1 -> else1Action]);
public func else2(actionHolder: IF2, action: func(): void): IF2
return checkAndAdd(actionHolder, action, IF2.Condition.else2);
public func none(actionHolder: IF2, action: func(): void): IF2
return checkAndAdd(actionHolder, action, IF2.Condition.none);
// finally, function which combines two conditions into a "trigger" for the if2 "statement"
public func if2(condition1: bool, condition2: bool): IF2.Condition
if (condition1 and condition2)
return IF2.Condition.both;
else if (condition1)
return IF2.Condition.else1;
else if (condition2)
return IF2.Condition.else2;
return IF2.Condition.none;
// private helper function to build the IF2 structure
func checkAndAdd(actionHolder: IF2, action: func(): void, actionName: IF2.Condition): IF2
if (actionHolder.actions.contains(actionName))
throw new Exception("action defined twice for one condition in if2");
actionHolder.actions[actionName] = action;
return actionHolder;
// helper structure to process the if2 "statement"
struct IF2
public enum Condition { both, else1, else2, none };
public var actions: Dict<Condition, func(): void>;
// usage
if2 (true, false) then func()
println("both true");
else1 func()
println("first true");
else2 func()
println("second true");
none func()
println("none true");
In file "if2macro.n":
// point of interest: the when keyword and && operator inside the macro definition are macros themselves
macro if2 (cond1, cond2, bodyTT, bodyTF, bodyFT, bodyFF)
syntax ("if2", "(", cond1, ")", "(", cond2, ")", bodyTT, "elseTF", bodyTF, "elseFT", bodyFT, "else", bodyFF)
when($cond1 && $cond2) {$bodyTT};
when($cond1 && !($cond2)) {$bodyTF};
when(!($cond1) && $cond2) {$bodyFT};
when(!($cond1) && !($cond2)) {$bodyFF};
Compile with:
ncc -r Nemerle.Compiler.dll -t:dll if2macro.n -o if2macro.dll
In file useif2.n:
using System;Compile with:
using System.Console;
module UseIf2
Main() : void
def happy = true;
def knowit = false;
if2 (happy) (knowit)
Write("Clap hands")
Write("You're happy")
Write("Cheer up")
Write("You're unhappy, cheer up");
ncc -r if2macro.dll useif2.n
(context 'if2)
(define-macro (if2:if2 cond1 cond2 both-true first-true second-true neither)
((eval cond1)
(if (eval cond2)
(eval both-true)
(eval first-true)))
((eval cond2)
(eval second-true))
(eval neither))))
(context MAIN)
> (if2 true true 'bothTrue 'firstTrue 'secondTrue 'else)
> (if2 true false 'bothTrue 'firstTrue 'secondTrue 'else)
> (if2 false true 'bothTrue 'firstTrue 'secondTrue 'else)
> (if2 false false 'bothTrue 'firstTrue 'secondTrue 'else)
import macros
proc newIfElse(c, t, e): PNimNode {.compiletime.} =
result = newIfStmt((c, t))
macro if2(x, y: expr; z: stmt): stmt {.immediate.} =
var parts: array[4, PNimNode]
for i in parts.low .. parts.high:
parts[i] = newNimNode(nnkDiscardStmt).add(nil)
assert z.kind == nnkStmtList
assert z.len <= 4
for i in 0 .. <z.len:
assert z[i].kind == nnkCall
assert z[i].len == 2
var j = 0
case $z[i][0].ident
of "then": j = 0
of "else1": j = 1
of "else2": j = 2
of "else3": j = 3
else: assert false
parts[j] = z[i][1].last
result = newIfElse(x,
newIfElse(y, parts[0], parts[1]),
newIfElse(y, parts[2], parts[3]))
if2 2 > 1, 3 < 2:
echo "1"
echo "2"
echo "3"
echo "4"
# Missing cases are supported:
if2 2 > 1, 3 < 2:
echo "1"
echo "3"
echo "4"
# Order can be swapped:
if2 2 > 1, 3 < 2:
echo "1"
echo "3"
echo "2"
echo "4"
Of course the language can be extended with GP functions (starting with version 2.4.2, these are closures).
GP can also be extended by adding C code directly to Pari:
if2(GEN c1, GEN c2, GEN tt, GEN tf, GEN ft, GEN ff)
if (gequal0(c1))
if (gequal0(c2))
return ff ? closure_evalgen(ff) : gnil;
return ft ? closure_evalgen(ft) : gnil;
if (gequal0(c2))
return tf ? closure_evalgen(tf) : gnil;
return tt ? closure_evalgen(tt) : gnil;
This function, when compiled to the file
if2.gp.so, can be loaded into GP with the following commands:
addhelp(if2, "if2(a,b,{seq1},{seq2},{seq3},{seq4}): if a is nonzero and b is nonzero, seq1 is evaluated; if a is nonzero and b is zero, seq2 is evaluated; if a is zero and b is nonzero, seq3 is evaluated; otherwise seq4. seq1 through seq4 are optional.");
Alternately, add these lines into the C course and run through gp2c-run:
GP;addhelp(if2, "if2(a,b,{seq1},{seq2},{seq3},{seq4}): if a is nonzero and b is nonzero, seq1 is evaluated; if a is nonzero and b is zero, seq2 is evaluated; if a is zero and b is nonzero, seq3 is evaluated; otherwise seq4. seq1 through seq4 are optional.");
Closures enable user-defined control structures, but the syntax is not always identical to that of built-in control structures. This example is a start, but needs improving.
use warnings;
use strict;
use v5.10;
=for starters
if2 condition1, condition2, then2 {
# both conditions are true
else1 {
# only condition1 is true
else2 {
# only condition2 is true
orelse {
# neither condition is true
Any (but not all) of the `then' and `else' clauses can be omitted, and else1
and else2 can be specified in either order.
This extension is imperfect in several ways:
* A normal if-statement uses round brackets, but this syntax forbids them.
* Perl doesn't have a `then' keyword; if it did, it probably wouldn't be
preceded by a comma.
* Unless it's the last thing in a block, the whole structure must be followed
by a semicolon.
* Error messages appear at runtime, not compile time, and they don't show the
line where the user's syntax error occurred.
We could solve most of these problems with a source filter, but those are
dangerous. Can anyone else do better? Feel free to improve or replace.
# All the new `keywords' are in fact functions. Most of them return lists
# of four closures, one of which is then executed by if2. Here are indexes into
# these lists:
use constant {
IdxThen => 0,
IdxElse1 => 1,
IdxElse2 => 2,
IdxOrElse => 3
# Most of the magic is in the (&) prototype, which lets a function accept a
# closure marked by nothing except braces.
sub orelse(&) {
my $clause = shift;
return undef, undef, undef, $clause;
sub else2(&@) {
my $clause = shift;
die "Can't have two `else2' clauses"
if defined $_[IdxElse2];
return (undef, $_[IdxElse1], $clause, $_[IdxOrElse]);
sub else1(&@) {
my $clause = shift;
die "Can't have two `else1' clauses"
if defined $_[IdxElse1];
return (undef, $clause, $_[IdxElse2], $_[IdxOrElse]);
sub then2(&@) {
die "Can't have two `then2' clauses"
if defined $_[1+IdxThen];
splice @_, 1+IdxThen, 1;
return @_;
# Here, we collect the two conditions and four closures (some of which will be
# undefined if some clauses are missing). We work out which of the four
# clauses (closures) to call, and call it if it exists.
use constant {
# Defining True and False is almost always bad practice, but here we
# have a valid reason.
True => (0 == 0),
False => (0 == 1)
sub if2($$@) {
my $cond1 = !!shift; # Convert to Boolean to guarantee matching
my $cond2 = !!shift; # against either True or False
die "if2 must be followed by then2, else1, else2, &/or orelse"
if @_ != 4
or grep {defined and ref $_ ne 'CODE'} @_;
my $index;
given ([$cond1, $cond2]) {
when ([False, False]) {$index = IdxOrElse}
when ([False, True ]) {$index = IdxElse2 }
when ([True, False]) {$index = IdxElse1 }
when ([True, True ]) {$index = IdxThen }
my $closure = $_[$index];
&$closure if defined $closure;
# This is test code. You can play with it by deleting up to three of the
# four clauses.
sub test_bits($) {
(my $n) = @_;
print "Testing $n: ";
if2 $n & 1, $n & 2, then2 {
say "Both bits 0 and 1 are set";
else1 {
say "Only bit 0 is set";
else2 {
say "Only bit 1 is set";
orelse {
say "Neither bit is set";
test_bits $_ for 0 .. 7;
Sample run:
[email protected]:~/perl$ ./if2
Testing 0: Neither bit is set
Testing 1: Only bit 0 is set
Testing 2: Only bit 1 is set
Testing 3: Both bits 0 and 1 are set
Testing 4: Neither bit is set
Testing 5: Only bit 0 is set
Testing 6: Only bit 1 is set
Testing 7: Both bits 0 and 1 are set
[email protected]:~/perl$
Perl 6[edit]
Writing the conditional blocks is no problem, since there's no distinction between built-in closures and user-defined. The if2 is currently just a function call, which requires a comma after the second condition; eventually we will be able to drop that in user-defined code, but none of our implementations can define parse actions in the statement_control category quite yet. (That syntax is special insofar as it's the only place Perl 6 allows two terms in a row.) So currently it requires the comma until the implementations catch up with the spec on that subject.
This solution is hygienic in both lexical and dynamic variables; the only caveat is that the user's program must avoid the dynamic variable being used by the implementation of conditional, $*IF2. This does not seem like a great hardship. (The conditionals will also nest correctly since that's how dynamic variables behave.)
my &if2 = -> \a, \b, &x { my @*IF2 = ?a,?b; x }
my &if-both = -> &x { x if @*IF2 eq (True,True) }
my &if-first = -> &x { x if @*IF2 eq (True,False) }
my &if-second = -> &x { x if @*IF2 eq (False,True) }
my &if-neither = -> &x { x if @*IF2 eq (False,False)}
sub test ($a,$b) {
$_ = "G"; # Demo correct scoping of topic.
my $got = "o"; # Demo correct scoping of lexicals.
my $*got = "t"; # Demo correct scoping of dynamics.
if2 $a, $b, {
if-both { say "$_$got$*got both" }
if-first { say "$_$got$*got first" }
if-second { say "$_$got$*got second" }
if-neither { say "$_$got$*got neither" }
say test |$_ for 1,0 X 1,0;
- Output:
Got both Got first Got second Got neither
Phix does not support macro programming. Generally I would suggest one of the following
switch {condition1,condition2} do
case {true,true}:
case {true,false}:
case {false,true}:
case {false,false}:
end switch
function if2(bool c1, bool c2)
return c1*10+c2
end function
switch if2(condition1,condition2) do
case 11:
case 10:
case 01:
case 00:
end switch
enum BOTH = 0b11, FIRST = 0b10, SECOND = 0b01, NEITHER = 0b00
function if2(bool c1, bool c2)
return c1*2+c2
end function
integer r = if2(condition1,condition2)
if r=BOTH then
elsif r=FIRST then
elsif r=SECOND then
elsif r=NEITHER then
end if
I can accept that those could all be deemed cheating (and that the last does not look anywhere near as nice as I hoped it would).
However Phix is designed to be easily modifiable (albeit not dynamically) and I think it would be instructive to outline the changes that would be needed to the compiler sources to achieve this task.
First decide on the syntax:
if2 condition1, condition2 then <block1> else1 <block2> else2 <block3> else <block4> end if2
and pseudocode to match the above (the last of the above three being the most suitable internally):
<tmp>=condition1*2+condition2 if <tmp>=0b11 then <block1> elsif <tmp>=0b10 then <block2> elsif <tmp>=0b01 then <block3> else <block4> end if
Next add new keywords. Find the last use of tt_stringF in pttree.e and add them. We do not know the ttidx values yet, so just duplicate the last one(5200)
global constant T_if2 = 5200 tt_stringF("if2",T_if2)
global constant T_else1 = 5200 tt_stringF("else1",T_else1)
global constant T_else2 = 5200 tt_stringF("else2",T_else2)
Then run p p and it will tell you what they should be
if2 should be 5208(not 5200) else1 should be 5216(not 5200) else2 should be 5224(not 5200)
Update the values and rebuild the compiler using "p -cp" (approx 10 seconds), then we can add the latter two to the block terminators (in pmain.e):
--constant T_endelseelsif = {T_end,T_else,T_elsif,T_case,T_default,T_fallthru,T_fallthrough}
constant T_endelseelsif = {T_end,T_else,T_else1,T_else2,T_elsif,T_case,T_default,T_fallthru,T_fallthrough}
Admittedly the next part is non-trivial. Not really worthwhile showing here, the distribution includes the file demo\rosetta\if2.txt which contains a DoIf2() procedure (120 lines) that is simply a quick hack of DoSwitch() and would be added to pmain.e
Lastly, that would need to be hooked in, find the DoSwitch call (again in pmain.e) and insert after it:
elsif ttidx=T_if2 then DoIf2()
Recompile Phix (p -cp, approx 10s) and test. Obviously, while I have subsequently removed it, I have tried this myself and it worked fine:
for N=10 to 20 do
printf(1,"%d is ",N)
if2 mod(N,2)=0, mod(N,3)=0 then
puts(1,"divisible by both two and three.\n")
puts(1,"divisible by two, but not by three.\n")
puts(1,"divisible by three, but not by two.\n")
puts(1,"neither divisible by two, nor by three.\n")
end if2
end for
- Output:
10 is divisible by two, but not by three. 11 is neither divisible by two, nor by three. 12 is divisible by both two and three. 13 is neither divisible by two, nor by three. 14 is divisible by two, but not by three. 15 is divisible by three, but not by two. 16 is divisible by two, but not by three. 17 is neither divisible by two, nor by three. 18 is divisible by both two and three. 19 is neither divisible by two, nor by three. 20 is divisible by two, but not by three.
module stmts;
import phl::lang::io;
/* LinkedList --> Each element contains a condition */
struct @ConditionalChain {
field @Boolean cond;
field @ConditionalChain next;
@ConditionalChain init(@Boolean cond, @ConditionalChain next) [
this::cond = cond;
this::next = next;
return this;
* If the condition is true executes the closure and returns a false element, otherwise returns the next condition
* Execution starts from the first element, and iterates until the right element is found.
@ConditionalChain then(@Closure<@Void> closure) [
if (isNull(next())) return new @ConditionalChain.init(false, null);
if (cond()) {
return new @ConditionalChain.init(false, null);
else return next();
/* Operators create a cool look */
@ConditionalChain operator then(@Closure<@Void> closure) alias @ConditionalChain.then;
@ConditionalChain operator else1(@Closure<@Void> closure) alias @ConditionalChain.then;
@ConditionalChain operator else2(@Closure<@Void> closure) alias @ConditionalChain.then;
@ConditionalChain operator orElse(@Closure<@Void> closure) alias @ConditionalChain.then;
/* Returns linked list [a && b, a, b, true] */
@ConditionalChain if2(@Boolean a, @Boolean b) [
return new @ConditionalChain.init(a && b, new @ConditionalChain.init(a, new @ConditionalChain.init(b, new @ConditionalChain.init(true, null))));
@Void main [
if2(false, true) then [
println("Not this!");
] else1 [
println("Not this!");
] else2 [
] orElse [
println("Not this!");
(undef 'if2) # Undefine the built-in 'if2'
(de if2 "P"
(if (eval (pop '"P"))
(eval ((if (eval (car "P")) cadr caddr) "P"))
(if (eval (car "P"))
(eval (cadddr "P"))
(run (cddddr "P")) ) ) )
(if2 (condition1isTrue) (condition2isTrue) (bothConditionsAreTrue) # A single expression in each of the (firstConditionIsTrue) # first three branches (secondConditionIsTrue) (noConditionIsTrue) # The final branch may contain (...) ) # an arbitrary number of expressions
As another example of language extension, see Anonymous recursion#PicoLisp.
function When-Condition
[Parameter(Mandatory=$true, Position=0)]
[Parameter(Mandatory=$true, Position=1)]
[Parameter(Mandatory=$true, Position=2)]
[Parameter(Mandatory=$true, Position=3)]
[Parameter(Mandatory=$true, Position=4)]
[Parameter(Mandatory=$true, Position=5)]
if ($Test1 -and $Test2)
return (&$Both)
elseif ($Test1 -and -not $Test2)
return (&$First)
elseif (-not $Test1 -and $Test2)
return (&$Second)
return (&$Neither)
Full syntax:
When-Condition -Test1 (Test-Path .\temp.txt) -Test2 (Test-Path .\tmp.txt) `
-Both { "both true"
} -First { "first true"
} -Second { "second true"
} -Neither { "neither true"
- Output:
neither true
Alternate syntax:
Set-Alias -Name if2 -Value When-Condition
if2 $true $false {
"both true"
} { "first true"
} { "second true"
} { "neither true"
- Output:
first true
Macro programming is heavily discouraged in the Python community. One of the central tenets is that the Python syntax be immutable so that no matter what code is run, you have the assurance that the languages syntax stays the same.
However; having said that, Python allows deep reflection and there are packages such as MacroPy that would allow this task to be accomplished.
It is not possible to extend the language by adding keywords or creating macros. This kind of behaviour can be faked be creating functions that take expressions and evaluating them. (The switch and ifelse functions are existing examples.)
if2 <- function(condition1, condition2, both_true, first_true, second_true, both_false)
expr <- if(condition1)
if(condition2) both_true else first_true
} else if(condition2) second_true else both_false
A test example:
for(x in 1:2) for(y in letters[1:2])
print(if2(x == 1, y == "a",
"both conditions are true",
x + 99,
yy <- rep.int(y, 10)
paste(letters[1:10], yy)
A variation that brings the syntax more in line with that described in the task is
if2 <- function(condition1, condition2, expr_list = NULL)
cl <- as.call(expr_list)
cl_name <- if(condition1)
if(condition2) "" else "else1"
} else if(condition2) "else2" else "else"
if(!nzchar(cl_name)) cl_name <- which(!nzchar(names(cl)))
The usage here is modified to
for(x in 1:2) for(y in letters[1:2])
print(if2(x == 1, y == "a", list(
"both conditions are true",
else1 = x + 99,
else2 =
yy <- rep.int(y, 10)
paste(letters[1:10], yy)
"else" = NULL
Racket, like other Schemes, makes this kind of thing almost trivial:
#lang racket
;; define a new syntax
;; this is the new syntax we want, in sexpr syntax:
(if2 condition1isTrue condition2isTrue
;; and this is the syntax that implements it:
(if condition1isTrue
(if condition2isTrue
(if condition2isTrue
;; ... and that's all you need -- it now works:
(define (try x y)
(displayln (if2 (< x 10) (< y 10)
"Both small"
"First is small"
"Second is small"
"Neither is small")))
(try 1 1) ; Both small
(try 1 10) ; First is small
(try 10 1) ; Second is small
(try 10 10) ; Neither is small
But as usual, Racket takes this much more seriously. For example, here is how the same looks in an upcoming infix-style language in Racket:
#lang honu var else1 = 1 var else2 = 1 macro if2 (else1 else2 else) { (condition1isTrue:expression) (condition2isTrue:expression) bothConditionsAreTrue:expression else1 firstConditionIsTrue:expression else2 secondConditionIsTrue:expression else noConditionIsTrue:expression} { syntax(if (condition1isTrue) { if (condition2isTrue) bothConditionsAreTrue else firstConditionIsTrue } else if (condition2isTrue) secondConditionIsTrue else noConditionIsTrue) } function try(x,y) { printf("~a\n", (if2 (x<10) (y<10) "Both small" else1 "First is small" else2 "Second is small" else "Neither is small")) } try(1, 1) // Both small try(1, 10) // First is small try(10, 1) // Second is small try(10, 10) // Neither is small
And here's another recent syntax experiment that was added:
#lang unstable/2d racket (require unstable/2d/cond) (define (try x y) (displayln #2dcond ╔═══════════╦═══════════════════╦════════════════════╗ ║ ║ (< x 10 ) ║ (>= x 10 ) ║ ╠═══════════╬═══════════════════╬════════════════════╣ ║ (< y 10 ) ║ "Both small" ║ "First is small" ║ ╠═══════════╬═══════════════════╬════════════════════╣ ║ (>= y 10) ║ "Second is small" ║ "Neither is small" ║ ╚═══════════╩═══════════════════╩════════════════════╝)) (try 1 1) ; Both small (try 1 10) ; First is small (try 10 1) ; Second is small (try 10 10) ; Neither is small
Since flow control is handled using combinators, we simply define a new one:
: 4wayIf ( flag flag both neither first second )
heap [ cons &cons dip [ [ cons ] dip ] dip rot ] preserve
[ do [ -1 = ] bi@ and ] [ 2drop do drop do ] when
[ do [ 0 = ] bi@ and ] [ 2drop do nip do ] when
[ do 0 = swap -1 = and ] [ drop nip do drop do ] when
[ do -1 = swap 0 = and ] [ drop nip do nip do ] when
drop 2drop ;
This is fairly noisy in terms of stack manipulations, but it's usage is clean and consistent with the rest of Retro:
: test
-1 -1 [ 1 ] [ 2 ] [ 3 ] [ 4 ] 4wayIf .s drop
0 0 [ 1 ] [ 2 ] [ 3 ] [ 4 ] 4wayIf .s drop
-1 0 [ 1 ] [ 2 ] [ 3 ] [ 4 ] 4wayIf .s drop
0 -1 [ 1 ] [ 2 ] [ 3 ] [ 4 ] 4wayIf .s drop ;
This REXX version is modeled after the ADA example.
Programming note: the two arguments for the if2 routine should be verified for having boolean values,
and also the number of arguments should be validated (both have been omitted to make the code clearer).
Usage example:
if2( some-expression-that-results-in-a-boolean-value, some-other-expression-that-results-in-a-boolean-value)
/*this part is a REXX comment*/ /*could be a DO structure.*/
select /*↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/ /*↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/
when if.11 /*{condition 1 & 2 are true}*/ then perform-a-REXX-statement
when if.10 /*{condition 1 is true}*/ then " " " "
when if.01 /*{condition 2 is true}*/ then " " " "
when if.00 /*{no condition is true}*/ then " " " "
/*an example of a DO structure for the first clause: */
when if.11 /*{condition 1 & 2 are true}*/ then do; x=12; y=length(y); end
/*REXX program introduces the IF2 "statement", a type of a four-way compound IF: */
parse arg bot top . /*obtain optional arguments from the CL*/
if bot=='' | bot=="," then bot=10 /*Not specified? Then use the default.*/
if top=='' | top=="," then top=25 /* " " " " " " */
w=max(length(bot), length(top)) + 10 /*W: max width, used for displaying #.*/
do #=bot to top /*put a DO loop through its paces. */
/* [↓] divisible by two and/or three? */
if2( #//2==0, #//3==0) /*use a new four-way IF statement. */
select /*now, test the four possible cases. */
when if.11 then say right(#,w) " is divisible by both two and three."
when if.10 then say right(#,w) " is divisible by two, but not by three."
when if.01 then say right(#,w) " is divisible by three, but not by two."
when if.00 then say right(#,w) " isn't divisible by two, nor by three."
otherwise nop /*◄──┬◄ this statement is optional and */
end /*select*/ /* ├◄ only exists in case one or more*/
end /*#*/ /* └◄ WHENs (above) are omitted. */
exit /*stick a fork in it, we're all done. */
if2: parse arg if.10, if.01 /*assign the cases of 10 and 01 */
if.11= if.10 & if.01 /* " " case " 11 */
if.00= \(if.10 | if.01) /* " " " " 00 */
return ''
10 is divisible by two, but not by three. 11 isn't divisible by two, nor by three. 12 is divisible by both two and three. 13 isn't divisible by two, nor by three. 14 is divisible by two, but not by three. 15 is divisible by three, but not by two. 16 is divisible by two, but not by three. 17 isn't divisible by two, nor by three. 18 is divisible by both two and three. 19 isn't divisible by two, nor by three. 20 is divisible by two, but not by three. 21 is divisible by three, but not by two. 22 is divisible by two, but not by three. 23 isn't divisible by two, nor by three. 24 is divisible by both two and three. 25 isn't divisible by two, nor by three.
Ruby uses a hopelessly egocentric combinator (aka a combinator in which Kx = K for all x) and anonymous classes inherited from that combinator to do the job:
# Define a class which always returns itself for everything
class HopelesslyEgocentric
def method_missing(what, *args) self end
def if2(cond1, cond2)
if cond1 and cond2
elsif cond1
Class.new(HopelesslyEgocentric) do
def else1; yield; HopelesslyEgocentric.new end
elsif cond2
Class.new(HopelesslyEgocentric) do
def else2; yield; HopelesslyEgocentric.new end
Class.new(HopelesslyEgocentric) do
def neither; yield end
[true,false].product([true,false]).each do |cond1, cond2|
print "%5s, %5s => " % [cond1, cond2]
if2(cond1, cond2) do
puts "both true"
end.else1 do
puts "first is true"
end.else2 do
puts "second is true"
end.neither do
puts "neither is true"
- Output:
true, true => both true true, false => first is true false, true => second is true false, false => neither is true
macro_rules! if2 {
($cond1: expr, $cond2: expr
=> $both:expr
=> $first: expr
=> $second:expr
=> $none:expr)
=> {
match ($cond1, $cond2) {
(true, true) => $both,
(true, _ ) => $first,
(_ , true) => $second,
_ => $none
fn main() {
let i = 1;
let j = 2;
if2!(i > j, i + j >= 3
=> {
// code blocks and statements can go here also
let k = i + j;
println!("both were true")
=> println!("the first was true")
=> println!("the second was true")
=> println!("neither were true")
Defining a new control construct:
scala> def if2[A](x: => Boolean)(y: => Boolean)(xyt: => A) = new {
| def else1(xt: => A) = new {
| def else2(yt: => A) = new {
| def orElse(nt: => A) = {
| if(x) {
| if(y) xyt else xt
| } else if(y) {
| yt
| } else {
| nt
| }
| }
| }
| }
| }
if2: [A](x: => Boolean)(y: => Boolean)(xyt: => A)java.lang.Object{def else1(xt: => A): java.lang.Object{def else2(yt: =>
A): java.lang.Object{def orElse(nt: => A): A}}}
scala> if2(true)(true) {
| 1
| } else1 {
| 9
| } else2 {
| 11
| } orElse {
| 45
| }
res0: Int = 1
scala> if2(false)(true) {
| "Luffy"
| } else1 {
| "Nami"
| } else2 {
| "Sanji"
| } orElse {
| "Zoro"
| }
res1: java.lang.String = Sanji
(define-syntax if2
(syntax-rules ()
((if2 cond1 cond2 both-true first-true second-true none-true)
(let ((c2 cond2))
(if cond1
(if c2 both-true first-true)
(if c2 second-true none-true))))))
Seed7 allows the definition of statement syntax and semantic.
$ include "seed7_05.s7i";
$ syntax expr: .if.().().then.().else1.().else2.().else3.().end.if is -> 25;
const proc: if (in boolean: cond1) (in boolean: cond2) then
(in proc: statements1)
(in proc: statements2)
(in proc: statements3)
(in proc: statements4)
end if is func
if cond1 then
if cond2 then
end if;
elsif cond2 then
end if;
end func;
const proc: main is func
if TRUE FALSE then
writeln("error TRUE TRUE");
writeln("TRUE FALSE");
writeln("error FALSE TRUE");
writeln("error FALSE FALSE");
end if;
end func;
Like most Lisps, this is trivial in Shen.
(defmacro branch-if-macro
[branch-if Cond1 Cond2 Both Fst Snd None] ->
[if Cond1
[if Cond2 Both Fst]
[if Cond2 Snd None]])
(define try
X Y -> (branch-if (integer? X)
(integer? Y)
both-ints first-int second-int neither-int))
(map (/. X (do (print X) (nl)))
[(try 1 2) (try 1 1.5) (try 1.5 1) (try 1.5 1.5)])
class if2(cond1, cond2) {
method then(block) { # both true
if (cond1 && cond2) {
return self;
method else1(block) { # first true
if (cond1 && !cond2) {
return self;
method else2(block) { # second true
if (cond2 && !cond1) {
return self;
method else(block) { # none true
if (!cond1 && !cond2) {
return self;
if2(false, true).then {
say "if2";
}.else1 {
say "else1";
}.else2 {
say "else2"; # <- this gets printed
}.else {
say "else"
The core of Tcl's language-level extensibility are the
uplevel and
upvar commands, which respectively allow execution of arbitrary code in the caller's context and provide safe access to variables in the caller's context. To create an
if2, only
uplevel is required (together with
list which does substitution-safe script generation as a side-effect):
proc if2 {cond1 cond2 bothTrueBody firstTrueBody secondTrueBody bothFalseBody} {
# Must evaluate both conditions, and should do so in order
set c1 [uplevel 1 [list expr $cond1]
set c2 [uplevel 1 [list expr $cond2]
# Now use that to decide what to do
if {$c1 && $c2} {
uplevel 1 $bothTrueBody
} elseif {$c1 && !$c2} {
uplevel 1 $firstTrueBody
} elseif {$c2 && !$c1} {
uplevel 1 $secondTrueBody
} else {
uplevel 1 $bothFalseBody
if2 {1 > 0} {"grill" in {foo bar boo}} {
puts "1 and 2"
} {
puts "1 but not 2"
} {
puts "2 but not 1"
} {
puts "neither 1 nor 2"
Which produces this output:
1 but not 2
Condition-free form[edit]
It's also possible to write this without any use of
if at all, through the careful selection of variable names:
proc if2 {cond1 cond2 body00 body01 body10 body11} {
# Must evaluate both conditions, and should do so in order
# Extra negations ensure boolean interpretation
set c1 [expr {![uplevel 1 [list expr $cond1]]}]
set c2 [expr {![uplevel 1 [list expr $cond2]]}]
# Use those values to pick the script to evaluate
uplevel 1 [set body$c1$c2]
This behaves exactly as above, so shall not be repeated here.
Other language extension forms[edit]
Tcl includes very strong support for language extension. For example, consider this code which implements a integer looping command:
proc loop {varName lowerBound upperBound body} {
upvar 1 $varName var
for {set var $lowerBound} {$var <= $upperBound} {incr var} {
uplevel 1 $body
That implements, in a few lines of code, a new looping construct that does integer iteration and which supports both
break and
continue, as any loop should. The loop variable is "owned" by the context which calls the loop, and the loop body can access all local variables. It's all also completely safe against complex substitutions. Here's an example of use:
proc timestables {M N} {
loop i 1 $M {
loop j 1 $N {
puts "$i x $j = [expr {$i * $j}]"
timestables 3 3
1 x 1 = 1 1 x 2 = 2 1 x 3 = 3 2 x 1 = 2 2 x 2 = 4 2 x 3 = 6 3 x 1 = 3 3 x 2 = 6 3 x 3 = 9
(defmacro if2 (cond1 cond2 both first second . neither)
(let ((res1 (gensym))
(res2 (gensym)))
^(let ((,res1 ,cond1)
(,res2 ,cond2))
(cond ((and ,res1 ,res2) ,both)
(,res1 ,first)
(,res2 ,second)
(t ,*neither)))))
UNIX Shell[edit]
Bourne shells never have custom control structures. One can fake them with runtime evaluation, but the result has ugly syntax and evaluates code in the wrong scope.
if2() {
if eval "$1"; then
if eval "$2"; then eval "$3"; else eval "$4"; fi
if eval "$2"; then eval "$5"; else eval "$6"; fi
if2 'test 7 -lt 9' 'test 7 -gt 9' '
echo both 1 and 2
' '
echo 1 but not 2
' '
echo 2 but not 1
' '
echo neither 1 nor 2
fn if2 cond1 cond2 body11 body10 body01 body00 {
# Must evaluate both conditions, and should do so in order.
# Negation ensures a boolean result: a true condition becomes
# 1 for false; a false condition becomes 0 for true.
let (c1 = <={! $cond1}; c2 = <={! $cond2}) {
# Use those values to pick the body to evaluate.
if2 {test 1 -gt 0} {~ grill foo bar boo} {
echo 1 and 2
} {
echo 1 but not 2
} {
echo 2 but not 1
} {
echo neither 1 nor 2
Identifiers can't contain digits, so the function is named
iftwo("p","q") <"both","justp","justq","neither"> =
The type of
iftwo is that of a function taking a pair of predicates and
returning a function that takes a list of four functions. A function of the form
iftwo(p,q) <f,g,h,i> applied to an argument
x will cause
each predicate to be applied to
x, and exactly one of
h(x) or
i(x) to be returned.
In general, almost anything about the language can be extended with sufficient effort, because most of the compiler's internal tables and data structures can be modified or substituted by the user. However, such extreme measures are not meant to be needed because higher order functions such as
iftwo can be routinely defined and used as shown.
- Programming Tasks
- Solutions by Programming Task
- Control Structures
- BBC BASIC/Omit
- Ada
- Clay
- Clojure
- Common Lisp
- Delphi
- EchoLisp
- Factor
- Forth
- FreeBASIC
- Haskell
- Icon
- Unicon
- Inform 7
- Kotlin
- Lasso
- Mathematica
- Wolfram Language
- Morfa
- Nemerle
- NewLISP
- Nim
- Perl
- Perl 6
- Phix
- PicoLisp
- PowerShell
- Python
- Racket
- Retro
- Ruby
- Rust
- Scala
- Scheme
- Seed7
- Shen
- Sidef
- Tcl
- UNIX Shell
- Es
- Ursala
- Ada/Omit
- Commodore BASIC/Omit
- C sharp/Omit
- Go/Omit
- Integer BASIC/Omit
- Java/Omit
- Lily/Omit
- NetRexx/Omit
- PureBasic/Omit
- Yorick/Omit
- Zkl/Omit


text:
UPDATE - Klopp ready to move to Premier League now
So Jurgen Klopp is set to leave Borussia Dortmund at the end of this season, but will his dream of managing in the Premier League become an instant reality?
Klopp has emerged as a strong contender to replace Manuel Pellegrini at Manchester City this summer, with his long-standing links with a possible move to replace Arsene Wenger when he steps down as Arsenal manager also set to be revived.
Yet after a challenging season that has seen Klopp fighting relegation with Dortmund for a time and coming under a barrage or criticism, reports in Germany suggesting he is looking to take a break from the game are wide of the mark.
"I am sure that the decision is absolutely right," he said as he confirmed he is about to leave Dortmund.
"It's not that I am tired, but this team deserves to have the absolutely one hundred percent right coach."
He also denied he has had contact with Premier League clubs as he stated. "I have no contact to another club, either in England or elsewhere. But I do not intend to put in a sabbatical year."
That final comment will fuel the theory that he or his advisers have been sounded out by Manchester City, with his eagerness in the Premier League a long standing goal.
Arsenal fans were quick to suggest he could be the man to replace long-serving boss Arsene Wenger, with one prominent fan urging his club to make the move to snap up Klopp now.
Klopp would be our Mourinho. The time has come, Arsenal - act. #KloppIN— Piers Morgan (@piersmorgan) April 15, 2015
Klopp's move for him to step away from his role is no surprise, as he has looked to have run out of ideas at times this season as he battled to keep Dortmund at the top of the game despite their policy of selling star names each summer became more difficult then ever this season.
Robert Lewandowski's departure to Bayern Munich at the end of last season and an injury to star man Marco Reus affected Dortmund's challenge in recent months and now comes that news that Klopp is leaving his job.
The coach who has won two Bundesliga titles with Dortmund and led them to the 2013 Champions League final will leave the club with his head held high and his reputation as one of the most astute coach's in Europe firmly established.
Where will he end up? That remains to be seen, but the fascinating story of Jurgen Klopp is only just beginning.

subset: commoncrawl


text:
Starbucks tables charge your devices in Silicon Valley
0. phoneArena posted on 29 Jul 2013, 17:18
Thanks to Duracell Powermat equipped tables, going to certain Starbucks in Silicon Valley will do more than just fuel yourself up with some caffiene; the tables will allow you to fuel up your mobile devices at the same time you are consuming your java. According to Duracell President Stassi Anastassov, just putting your device on the table will start the recharging process...
This is a discussion for a news. To read the whole news, click here
1. Omarc07 (Posts: 481; Member since: 12 Nov 2012)
I want this in LA as I go to starbucks 3-4 times a week.
2. alpinejason (Posts: 262; Member since: 06 Sep 2011)
And Houston as well.
3. rallyguy (Posts: 620; Member since: 13 Mar 2012)
I thought Starbucks was trying to discourage people from hanging out for long periods of time?
4. WakaFlakaD (Posts: 527; Member since: 30 Apr 2011)
It's about time!
5. StalkinUrMom (Posts: 111; Member since: 16 Apr 2012)
Great, all the hipsters could pretty much live there now, lol.
6. PapaSmurf (Posts: 10457; Member since: 14 May 2012)
Because the Starbucks in Chicago aren't always packed already. Finding a seat next year will be a goal on peoples' bucket list. :/
7. JMartin22 (Posts: 2013; Member since: 30 Apr 2013)
I admire their business strategy to attract people that would be willing to purchase their overpriced coffees and lattes.


text:
30 Minutes Proofreading
I am a writing center tutor and English teacher. I have over 5 years in professional proofreading experience. Additionally, I can identify the patterns in your errors to let you know how to improve in the future.
Training & Qualifications
I have a Bachelor's and a Master's in English. I work as an English teacher and a Writing Center tutor.
Availability & Preferences
Depends every day.
About Elizabeth L
I'm new to the site! Feel free to ask. Apparently there's a two hundred word minimum, but as I am just trying to get a feel for the site, I would rather not put too much information quite yet. I wil...l post descriptions on every skill that I offer. show moreOpen to other proposals
Elizabeth L is looking for:
- Fun & Quirky
- Learning
- Travel
- Art & Design


text:
Job Title: Teacher
Type of Company: I work for a four-school city school system.
Education: BA, Special Education MA, Elementary Education National Board Certified Teacher
Previous Experience: I worked as a substitute teacher for two years before starting to teach full-time.
Job Tasks: As a sixth grade science and math teacher, I begin my day by taking attendance and finding out about my students' day. I plan appropriate lessons, grade papers, set up labs and meet with my colleagues during planning time. In science, we study the earth, the environment and space, using hands-on science lessons as often as possible. There are several outdoor lessons which require students to make and maintain a journal. In math, my students work out real world problems using basic computations, geometry, and algebra. Students are required to take practice tests and work toward passing a state-mandated test.
At times, I am required to handle discipline issues. This is done through discussions of the behavior, alternative choices, and consequences.
Meetings consume a large part of the day. Teachers meet with their team to discuss upcoming events; they also meet with professional learning communities in order to best meet the needs of students. Grading systems are established and I am required to send home newsletters, progress reports, and report cards. Student interaction is key to making sure that understanding of ideas is maintained. Cooperative learning groups are established in order to teach students to interact with peers to meet a common goal. Computer knowledge is used at times, but is limited due to the lack of computer systems.
Certain non-teaching duties are also assigned to me. Often I have to do breakfast duty, overseeing the behavior of students who come to school early for breakfast. I also eat in the cafeteria with students in order to distribute lunch fund money to kids who came to school without lunch money. Field trips and other extracurricular activities are planned and organized. Monies must be collected and receipted. Accurate records must be maintained. As a coach of tennis and swimming, I meet with my athletes, conduct practice and organize matches and meets.
Best and Worst Parts of the Job: The best part of the job is spending time with the students learning new things. I get to plan activities that should be interesting and educational. It is exciting when a student learns a new skill or makes a new discovery.
The paperwork is the worst part of the job. Keeping records and maintaining accounts is very tedious and boring.
Job Tips:
1. Spend as much time as possible learning the curriculum. 2. Take classes on classroom management. 3. Keep files for various subjects and grades. 4. Make the most of your student teaching experience. 5. Observe other teachers and make notes of what you see. 6. Keep a notebook of ideas that you gather from other teachers.
Additional Thoughts: A teacher must be flexible and must maintain his integrity at all costs.
Click the Visit School Site buttons to go directly to a school's website and learn more about the school and programs it has to offer. School website will open in a new tab. .
Click the Request Info buttons to request more information from a representative at the school
Concordia University - Portland offers several fully online 14-month Master of Education (M.Ed.) programs and a fully online Doctorate of Education (Ed.D.) program.
Want to be a Teacher or Educational Administrator? Learn why GCU could be the best place to start!
100% Online & No Standardized Testing
Ashford University
Abilene Christian University is a national leader in Christian higher education and a place where students, faculty, staff and alumni make a real difference in the world.
Since 1977, Keiser University has provided quality student-centered, career-focused education.
At Post University, we believe you shouldn't have to put your life on hold to further your education.
Founded by the Society of Jesus in 1851, Saint Joseph's University (SJU) has been developing the minds and abilities of men and women in a challenging academic environment steeped in the enriching Jesuit tradition of cura personalis (care of the entire person).
Colorado State University-Global Campus
Colorado State University-Global Campus (CSU-Global) offers career relevant bachelor's and master's degree programs for working adults and nontraditional learners.
Earn your graduate degree online with Northcentral University.
The inside stories from people actually working in the field.
Click a story title to show the story, and click the title again to hide it.
All Types
Career Stories are concise, real-world career overviews written by people relating their personal career experiences and wisdom. They provide invaluable insights and mentoring advice to students and career changers.
Most stories include:
Please also see our detailed information about Middle School Teachers, including:


text:
Please Like and Share to Support Us
Runtime: 134 mins
Genres Biography Drama Sport Thriller
Actors Channing Tatum, Steve Carell, Mark Ruffalo, Sienna Miller, Vanessa Redgrave, Anthony Michael Hall, Guy Boyd, Brett Rice, Jackson Frazer, Samara Lee, Francis J. Murphy III, Jane Mowder, David Bennett, Lee Perkins, Robert Haramia, Daniel Hilt, Bryan Cook, David Zabriskie, Zach Rey, Reece Humphrey, J.D. Bergman, Corey Jantzen, Frederick Feeney, Mark Schultz, Lee Kemp, Jake Herbert, Donald Modrick, Gabrielle Burton, Kevin Cooke, Richard E. Chapla Jr.
watch Foxcatcher 2014 online free The greatest Olympic Wrestling Champion brother team joins Team Foxcatcher lead by multimillionaire sponsor John E. du Pont as they train for the 1988 games in Seoul – a union that leads to unlikely circumstances
Foxcatcher (2014) Watch Links
Tips: If movie does not play, please reload the page and try again important If u can not see the movie then please open the site with different web browser eg firefox/Chrome /puffin browser /Safari. NOTE plz do let the movie load like 10/15 mins otherwise u may get into buffering problem/freeze. still cant watch? check how to watch page for more info


text:
Hi lovelies! It's Chinwe Juliet here and today we are going to be talking about how to make natural hair soft and how to maintain it throughout the week. 🤗 Natural Hair FACT Our hair loves Keep Reading
The Ultimate Hack for Maintaining Natural Hair between ...
I have been using this method for the past 5 years and yes my hair is still very healthy. There are a number of hacks for natural hair but over the weekend, I released Keep Reading
5 Ways to Style Natural Hair for Weddings, Prom & ...
Natural Hairstyles for Weddings, Prom and Special Occasions Do you have a wedding coming up soon? Or maybe you are a guest to a special occasion, probably your prom or graduation is coming up and Keep Reading
Tips for Waking Up with Beautiful Hair
Tips for Waking Up with Beautiful Hair As indicated in an earlier post entitled '25 Tricks and Tips for Growing and Maintaining Natural Hair', one of the easiest ways to keep your hair in place and Keep Reading
10 Benefits & Uses of Shea Butter and Coconut Oil
If you haven't heard of the amazing benefits of Shea butter and Coconut oil here are 10 benefits of these natural goodies that you need to know. Shea Butter If you want softer skin, shea butter Keep Reading
Read Me-Igbocurls App
For those of you receiving updates via my App, notifications link to posts under Blog when you click on the Menu button. I apologize for the inconvenience as I seek to address this issue in Keep Reading
Growth = More Responsibilities
Hi, lovelies! First of all, I want to thank you all for keeping my website traffic constant despite my silence. I have been working on several personal projects to bring you all insightful, informative and Keep Reading
Igbocurls App Tip of the Day
There is no such thing as 'BAD Hair'. Only poorly treated hair. You and your hair will not achieve your growth potential if you don't seek the right information and knowledge and act on it. Keep Reading
LIPSTICKS Now Available on ShopIgbocurls.com
You all know I hardly take pictures without lipsticks, that's how much I love them. So as fate will have it, I came across an opportunity to stock some Big Name International Beauty Brands like HudaBeauty, Keep Reading
How To Stretch Natural Hair Without Heat – Braid ...
I always get asked how I stretch natural hair without heat so I started a series on my YouTube Channel to show you all the different ways I do so. I plan on making my Keep Reading


text:
Alif Academy
Catchment Area
Academic Results
Parents Forum
Buy & Sell
About Alif Academy
Alif Academy is a Academy school located in London. The Headteacher is .
Contact Information
Alif Academy 313-319 Katherine Road, London, Greater London, E7 8PJ
020 8552 4375
020 7780 1794
Other Info
- Type: Academy
- Headteacher:
- Gender: Co-ed
- Total on roll: 114
View the official OFSTED report for Alif Academy
School Catchment Area
Academic Results
Parents Forum
New and exclusive to School Reviewer is our new parent's forum. Join other parents to discuss issues and topics that are relevant to your school, or join our national forum to discuss, ask or give advice on topics that matter to all parents. Get involved and start the conversation!
Buy & Sell
School Reviewer's new and unique Buy and Sell section Sell your child's outgrown uniforms, no longer needed books or any other items on your local selling platform. Welcome to the new and simple way to buy and sell unwanted school items.
Category Name: ALL
No reviews yet


text:
|Home | About | Journals | Submit | Contact Us | Français
Lateralization of brain connectivity may be essential for normal brain function and may be sexually dimorphic. Here, we study the laterality patterns of short-range (implicated in functional specialization) and long-range (implicated in functional integration) connectivity and the gender effects on these laterality patterns. Parallel computing was used to quantify short- and long-range functional connectivity densities in 913 healthy subjects. Short-range connectivity was rightward lateralized and most asymmetrical in areas around the lateral sulcus, whereas long-range connectivity was rightward lateralized in lateral sulcus and leftward lateralizated in inferior prefrontal cortex and angular gyrus. The posterior inferior occipital cortex was leftward lateralized (short- and long-range connectivity). Males had greater rightward lateralization of brain connectivity in superior temporal (short- and long-range), inferior frontal, and inferior occipital cortices (short-range), whereas females had greater leftward lateralization of long-range connectivity in the inferior frontal cortex. The greater lateralization of the male's brain (rightward and predominantly short-range) may underlie their greater vulnerability to disorders with disrupted brain asymmetries (schizophrenia, autism).
Brain anatomy and function differ for the left and right hemispheres of the human brain, which is believed to reflect not only the emergence of language but also developmental and genetic factors (Toga and Thompson 2003). Brain asymmetry is present at the structural level in the fetal brain in humans and nonhuman primates (Galaburda et al. 1978) and appears to be disrupted in patients with autism spectrum disorder (ASD), schizophrenia, and developmental dyslexia (Saugstad 1999).
Brain laterality differences between the genders have also been documented and may underlie gender differences in cognitive styles (Proust-Lima et al. 2008). For example, the females' overall linguistic advantage over males may reflect stronger leftward lateralization of the language networks, whereas the males' spatial skills advantage over females may reflect stronger rightward lateralization of visuospatial networks (Clements et al. 2006). Gender differences in the lateralization of brain function might also contribute to gender differences in the incidence of neurospychiatric disorders such as ASD (Baron-Cohen et al. 2005) and schizophrenia (Narr et al. 2001). However, the gender differences in the lateralization of brain function are still controversial, and few studies have been done to address it. For example, whereas some blood oxygen level–dependent-functional magnetic resonance imaging studies have suggested that lateralization of language might be more pronounced in males than in females (Shaywitz et al. 1995) others have failed to reproduce these gender effects (Frost et al. 1999).
Intrinsic brain activity captured during brief (5–10 min) magnetic resonance imaging (MRI) scanning during resting conditions (Biswal et al. 1996; Biswal et al. 2010) can now be used to evaluate local and distant functional connectivity (Sepulcre et al. 2010), including the assessment of functional brain asymmetry (Liu et al. 2009) in the male and in the female brain. Studies based on 200 seed regions of interest (ROIs) distributed uniformly in the brain reported a small but significant gender by laterality interaction effect on the strength of the functional connectivity (stronger in males than in females) between seed regions (Liu et al. 2009). However, the asymmetry of short- or long-range functional connections and their interactions with gender have not been evaluated.
Recently, we proposed functional connectivity density mapping (FCDM), a voxelwise data-driven technique to assess the short-range (local) functional connectivity density (lFCD) (Tomasi and Volkow 2010). Here, we describe a novel method based on FCDM and a standard graph theory approach to separately assess short- and long-range FCD, which we used to map the laterality patterns of functional connectivity and to evaluate gender effects in 913 subjects from a large public MRI database (Biswal et al. 2010). A simple parallel computing method was used to speed up significantly (1000 times faster) the overwhelming computation of graph theory measures of global functional connectivity density (gFCD) at 3-mm isotropic spatial resolution. Based on documented anatomical and functional rightward asymmetries (Devlin et al. 2003; Toga and Thompson 2003; Schönwiesner et al. 2007; Okamoto et al. 2009), we hypothesized that temporal and cingulate cortices would show a rightward lateralization for both short- and long-range FCD. We also predicted that the laterality of the short- and long-range FCD patterns would show significant gender effects in a regional specific manner.
Functional scans that were collected in "resting-state" conditions and correspond to 913 healthy subjects (Table 1) from 19 research sites of the "1000 Functional Connectomes" Project (http://www.nitrc.org/projects/fcon_1000/) were included in the study. Data sets from other research sites that were not available at the time of the study (pending verification of IRB status) did not report demographic variables (gender and age), exhibited image artifacts that prevented the study of short- and long-range FCD, or did not meet the imaging acquisition criteria (3 s ≥ repetition time, full brain coverage, time points > 100, spatial resolution better than 4 mm) were not included in the study.
The statistical parametric mapping package SPM2 (Wellcome Trust Centre for Neuroimaging, London, UK) was used for image realignment and spatial normalization to the stereotactic space of the Montreal Neurological Institute (MNI) using a 12-parameter affine transformation with medium regularization, 16-nonlinear iterations, voxel size of 3 × 3 × 3 mm3. Other preprocessing steps were carried out using IDL (ITT Visual Information Solutions, Boulder, CO). A multilinear regression approach that used the time-varying realignment parameters (3 translations and 3 rotations) was applied to minimize motion related fluctuations in the MRI signals (Tomasi and Volkow 2010), and the global signal intensity was normalized across time points. Band-pass temporal filtering (0.01–0.10 Hz) was used to remove magnetic field drifts of the scanner (Foerster et al. 2005) and minimize physiologic noise of high frequency components (Cordes et al. 2001). Voxels with signal-to-noise (as a function of time) < 50 were eliminated to minimize unwanted effects from susceptibility-related signal-loss artifacts on FCDM. MRI time series reflecting the preprocessing steps were saved in hard drive for subsequent analyses.
The preprocessed image time series underwent FCDM to compute the strength of the lFCD (Tomasi and Volkow 2010). The number of local connections at every voxel location x0, k(x0), was determined through Pearson correlations between time-varying signals at x0 and those from its closest neighbors using an arbitrary threshold R > 0.6 (Tomasi and Volkow 2010, 2011a, 2011b, 2011c, 2011d). This correlation threshold was selected in our previous work because R < 0.4 increased false positive rate and CPU time and R > 0.7 lead to lFCD maps with reduced dynamic range and lower sensitivity; thus we fixed R = 0.6 for all calculations (Tomasi and Volkow 2010). In addition, standard graph theory (degree centrality) was used to map the strength of the gFCD from the preprocessed image time series (Tomasi and Volkow 2011c) (for a complete collection of graph theory measures, see Rubinov and Sporns 2010). Two voxels were considered functionally connected if the Pearson linear correlation factor R > 0.6; we selected this correlation threshold to be consistent with that used to compute the lFCD maps. We verified that the rescaled gFCD (normalized to its mean value in the whole brain) was stable under threshold variations in the range 0.5 < R < 0.7. The gFCD at a given voxel x0 was computed as the global number of functional connections, k(x0), between x0 and all other N − 1 = 57712 voxels in the brain. This calculation was repeated for all x0 voxels in the brain and involved the computation of a N2 correlation matrix.
A simple approach based on data parallelism was implemented to speed up the calculation of the gFCD by taking advantage of multiprocessor computer architectures. Specifically, the data was distributed across processing nodes in a way that all nodes executed the same code (gFCD.exe; 32 bit) on different imaging data (1 gFCD.exe per subject, 2 subjects per core). The standalone gFCD.exe code (188 kB) efficiently allocated 128 MB of dynamic memory via pointer reference by setting the handler mode for malloc, a standard C subroutine for fast operations on random-access memory. The gFCD.c code was developed and compiled using Visual C++ 6.0 (Microsoft Corp, Redmond, WA). Thus, the computation of the gFCD maps required only 120 min/subject (single core PC without Hyper-Threading Technology [HTT]), which was significantly faster than what could be achieved using user-friendly high-level programing languages such as IDL or Matlab (~few days per subject).
A workstation with 2 Intel Xeon X5680 processors (6 cores per processor, 12 MB L3 Cache, 64-bit, 3.33 GHz), which accounted a total of 12 cores and allows 24 processing threads with HTT, running Windows 7 (64-bit) was used to compute the gFCD maps for each subject. Note that HTT enabled the operating system to address 2 virtual processors for each of the 12 cores that were physically present. Twenty-four batches of jobs (gFCD.exe) were submitted simultaneously by terminal commands; Windows 7 distributed the workflow among the 24 virtual processors. Thus, our simple but efficient parallelization approach allowed us to compute 24 subjects (1 subject per virtual processor) at once and required in average only 5 min/subject to complete.
The lFCD included all voxels that belonged to the local cluster of functionally connected voxels. Since it predominantly reflects the regional short-range functional connectivity, we defined: short-range FCD = lFCD. Since the gFCD included both local and distal connections, we defined long-range FCD = gFCD − lFCD (Tomasi and Volkow 2011a). These maps inherited the radiological convention (left is right) of the native images. Short- and long-range FCD maps were spatially smoothed (8 mm) in SPM to minimize the differences in the functional anatomy of the brain across subjects.
We developed a voxelwise method to compute the laterality of the brain's functional connectivity that contrasts FCD measures at homologous voxels in the left and right hemispheres. For this purpose, short- and long-range FCD maps with neurological convention (R: right is right) were additionally created by flipping (as mirror reversal of) the radiological FCD maps (L) across the x-axis. Then, the strength and direction of the short- and long-range FCD asymmetries were mapped voxel-by-voxel by using a laterality index (LI) (Steinmetz 1996):
which partially accounts for intersubject variability and differential acquisition protocols among research sites. Negative LI values indicate leftward asymmetry and positive LI values indicate rightward asymmetry. The Fisher transform was used to normalize the step distributed LI values. Short- and long-range LI maps were spatially smoothed (8 mm) to minimize the differences in the functional anatomy of the brain across subjects. Group analyses of these LI maps were carried out in SPM using a 2-way analysis of variance (ANOVA) model with 2 conditions (short- and long-range FCD), 2 groups (males and females), and 1 covariate (age). Voxels with a conservative PFWE < 0.05, corrected for multiple comparisons in the whole brain with a familywise error (FWE) correction at the voxel-level were considered statistically significant across subjects. The population-average landmark- and surface-based atlas of the cerebral cortex (Van Essen 2005) provided in the installation package of the MRIcron image viewer (http://www.nitrc.org/projects/mricron) was used to identify FCD clusters with Brodmann areas (BAs) in the stereotactic space of the MNI.
Isotropic cubic masks containing 27 imaging voxels (0.73 mL) were defined at the coordinates of the cluster centers in the right hemisphere (Table 2) and their homologous regions in the left hemisphere to extract the average strength of the laterality of the short- and long-range FCD from individual LI maps and using a custom program written in IDL. The volume-of-interest (VOI) measures were used to assess the significance of the laterality findings as well as that of gender (assessed with parametric t-test and nonparametric Kolmogorov–Smirnov and Mann–Whitney–Wilcoxon tests) effects in Statview (SAS Institute Inc., Cary, NC) and Microcal Origin (Microcal Software Inc., Northampton, MA).
The average distribution of the short-range FCD was maximal in posterior cingulate and ventral precuneus (Fig. 1A). Other regions with high amplitude of short-range FCD included ventral occipital (cuneus), posterior lateral parietal (angular gyrus), and ventral and dorsolateral prefrontal cortices. The average distribution of the long-range FCD was maximal in the visual cortex, followed by posterior cingulate and ventral precuneus (Fig. 1B). Angular gyrus, superior and inferior parietal, and dorsolateral prefrontal and temporal cortices also had significant long-range FCD. Note that the patterns of these highly connected regions (both short- and long-range) had a similar distribution in the left and in the right hemisphere. Overall, the short- and long-range FCD were lower for subcortical than for cortical regions.
The statistical analysis of the LI patterns across all 913 subjects revealed that the short-range FCD was predominantly right lateralized and, except for the angular gyrus, included regions with low FCD. Regions showing a rightward asymmetry in short-range FCD were located in the vicinities of the lateral sulcus, including superior and middle temporal gyri (BAs 21, 22, 40, 41, and 42) and in the postcentral gyrus (BA 3). Smaller regions in prefrontal cortex (BAs 6, 11, and 47), insula (BA 13), and temporal pole (BAs 20 and 38) also exhibited rightward asymmetry. Regions showing a leftward asymmetry in short-range FCD were restricted and included small areas in the posterior cingulate (BA 29), inferior posterior (BA 17) and superior occipital cortex (BA 19), frontoparietal cortices (BAs 6 and 8), angular gyrus (BA 19/39), and hippocampus (Fig. 2A and Table 2). Temporal and inferior posterior occipital cortices showed the largest short-range laterality effects (LI = 22.1 ± 0.6% and −16.8 ± 0.6%, respectively; mean ± standard error).
As for the short-range FCD, the long-range FCD was predominantly right lateralized around the lateral sulcus (LI = 17.8 ± 0.7%) and left lateralized in the inferior posterior occipital cortex (LI = −12.7 ± 0.5%; Fig. 2B and Table 2) but also showed strong rightward lateralization in anterior and dorsal cingulate cortex (including BAs 23, 24, 31, and 32) and strong leftward lateralization in the frontal cortex (Broca's area, which encompasses pars opercularis, BA 44; pars transversalis, BA 45; and pars orbitalis, BA 47) and in the angular gyrus (BA 19/39). Comparisons of the laterality pattern for short- versus long-range FCD showed an opposite pattern in inferior orbital frontal cortex (pars orbitalis; BA 47) that showed leftward laterality in long-range FCD but rightward laterality for short-range FCD (Table 2).
The VOI analysis of short- and long-range FCD in homologous regions of the left and right hemispheres (Fig. 3) revealed that caudate had the strongest rightward lateralization both for short-range (22.2 ± 1.3%) and long-range (37.8 ± 2.5%) FCD and that temporal pole, superior temporal, and middle orbital frontal gyri also showed strong rightward lateralization for both short- and long-range FCD (>7.3%). The rightward lateralization in cingulate cortex and thalamus was strong for long-range FCD (>7.3%) but much weaker for short-range FCD (<3.7%). The strongest leftward lateralization occurred at the middle frontal gyrus, both for short-range (−30.5 ± 1.8%) and long-range (−11.9 ± 0.6%) FCD; the calcarine and posterior cingulate cortices, pars inferior frontal triangularis, and supplementary motor area also showed strong leftward lateralization for both short- and long-range FCD. The leftward lateralization in angular gyrus was strong for long-range FCD (−18.8 ± 1.1%) but much weaker for short-range FCD (−3.5 ± 0.2%). The inferior orbital frontal (pars orbitalis) exhibited strong leftward lateralization of long-range FCD (−15.0 ± 0.8%) and weak rightward lateralization of short-range FCD (1.1 ± 0.1%).
The group analysis revealed significant gender effects in the laterality of FCD (Fig. 4), although these were limited to small brain regions. The short-range FCD revealed significantly greater laterality in males (N = 408) than females (N = 505). This included higher rightward lateralization on short-range connectivity in inferior frontal (pars orbitalis, triangularis, and opercularis) and superior temporal and inferior parietal (postcentral gyrus) cortices (Fig. 4 and Table 3). The long-range connectivity in males showed higher rightward lateralization in superior temporal cortex, whereas females showed greater leftward lateralization of long-range connectivity in the inferior frontal cortex areas where males showed higher rightward lateralization for short-range connectivity (Fig. 4 and Table 3).
Regions with high functional connectivity may play an important role for the optimal efficiency and integration of functional networks both at rest and during task conditions (Biswal et al. 1995; Tomasi and Volkow 2011b) and could be critical to minimize the number of steps to connect any pair of neurons (Bassett and Bullmore 2006; Bullmore and Sporns 2009). An unbalance between short- and long-range FCD might result in pathology, as suggested by studies in patients with ASD who showed increased short-range and reduced long-range connectivity (Anderson et al. 2011; Barttfeld et al. 2011).
In this study, we evaluate for the first time the laterality patterns that emerge from resting-state functional connectivity data sets, separately for short- and for long-range FCD, and assess the gender effects on these patterns at an unmatched spatial resolution (3-mm isotropic). The main findings of the study are: 1) in resting conditions, the FCD was right lateralized in precuneus, superior parietal, temporal, and middle frontal cortices (short- and long-range) and in inferior orbital frontal (short-range) and cingulate (long-range) cortices and left lateralized in posterior occipital, superior frontal, lateral parietal, and posterior cingulate cortices (short- and long-range) and in the inferior frontal cortex (long-range) and 2) males had greater rightward laterality of brain connectivity in superior temporal, inferior frontal, and inferior occipital cortices (short-range) and in the superior temporal cortex (long-range) than females, whereas females showed greater leftward lateralization of long-range connectivity in inferior frontal cortex.
The voxelwise analysis revealed a rightward lateralization of the short- and long-range FCD in a large region of the temporal cortex (including superior and medial temporal gyri) and in inferior frontal gyri that to our knowledge had not been previously reported. The rightward lateralization likely reflects interhemispheric differences in the anatomy of the temporal cortices such as the larger extend of the Silvian fissure (which bordered the area that on our analyses showed the largest rightward laterality) on the right hemisphere than on the left (LeMay and Kido 1978; Kertesz et al. 1986). However, this lateralization pattern could also reflect in part the high levels of acoustic noise emitted by the MRI scanner during echo planar imaging acquisition (Tomasi et al. 2005) since sound processing (Devlin et al. 2003; Schönwiesner et al. 2007; Okamoto et al. 2009), including auditory motion perception is right lateralized (Hirnstein et al. 2007), which is likely to have enhanced brain activity predominantly in the right temporal cortex. Abnormal hemispheric asymmetries particularly in the Heschl's gyrus (auditory cortex) were associated with auditory hallucinations (Chance et al. 2008) and those in frontal areas have been implicated in schizophrenia (Bear et al. 1986; Chance et al. 2005).
The rightward asymmetry of the long-range FCD in cingulate cortex is consistent with prior studies reporting higher resting functional connectivity of the right cingulate cortex with prefrontal and parietal cortices than the left (Yan et al. 2009). The lateralization in cingulate cortex is also consistent with the structural asymmetries reported for the cingulate (Huster et al. 2007) and paracingulate cortices (Paus et al. 1996). Rightward lateralization of the cingulate cortex was more pronounced for females than for males and may be clinically significant since loss of the asymmetry in the anterior cingulate cortex was reported in female patients with schizophrenia (Takahashi et al. 2002). Our findings did not corroborate the rightward asymmetry of the functional connectivity strength in occipital–parietal cortices and insula previously reported in young adults using an ROI approach that did not distinguish between short- and long-range connections (Liu et al. 2009). However, methodological differences between studies might account for this discrepancy. Specifically, the LI used by Liu et al. contrasted the strength of the differential ipsilateral versus contralateral functional connectivity between hemispheres using 200 arbitrary ROI in each hemisphere. The present study is based on a larger sample and used a voxelwise and data-driven approach with a simple LI that reflects differences in connectivity density between hemispheres.
The leftward lateralization of short- and long-range FCD in posterior occipital cortex likely reflects the occipital petalia (LeMay 1976), a protrusion of the left hemisphere relative to the right (Toga and Thompson 2003). The leftward asymmetry of the long-range FCD in inferior prefrontal cortex and angular gyrus is consistent with previous resting-state studies on functional connectivity (Liu et al. 2009). The leftward lateralization is also likely to reflect the lateralization of language to the left hemisphere. Though traditionally, language production has been associated to Broca's area (BAs 44 and 45), a premotor area in BA 6 that controls complex articulations is also implicated (Price 2010). Similarly, language comprehension that is ascribed to Wernicke's area (predominantly includes posterior BA 22) also encompasses BAs 20, 21, 38, and 39 (Price 2010). Morphological studies have shown the leftward asymmetry of Broca's area and of the planum temporale (adjacent to angular gyrus) in humans (Falzi et al. 1982; Steinmetz 1996; Amunts et al. 1999) and nonhumans primates (Yeni-Komshian and Benson 1976), and abnormalities in the leftward asymmetry of language areas have been implicated in developmental dyslexia (Hynd et al. 1990; Larsen et al. 1990; Galaburda 1995) and schizophrenia (Crow et al. 1989; Bilder et al. 1999; Narr et al. 2001).
There were significant laterality differences between short- and long-range FCD. Most notable, a leftward lateralization was observed for the long-range but not for the short-range FCD in inferior frontal cortex and angular gyrus. Similarly, an opposite laterality pattern was observed in posterior cingulate (BA 29) and thalamus (pulvinar) for the short-range (leftward) versus the long-range (rightward) FCD. The functional significance of these laterality differences is unclear. However, since long-range cortical connections are implicated in functional integration (Bressler 1995) and local connections are implicated in functional specialization (Schroeder and Lakatos 2009), we speculate that differences in asymmetry between long- and short-range FCD could reflect differences in integration and specialization between the hemispheres.
The most prominent gender difference in the laterality of FCD occurred in the superior temporal cortex where males had stronger rightward lateralization of short- and long-range FCD than females. This finding is consistent with a stronger lateralization of superior temporal cortex functions in men than in women (Weekes et al. 1976). These gender differences could reflect testosterone levels during fetal development, which are higher for males than for females and can influence neural connectivity by averting programed cell death during neural development (De Vries and Simerley 2002). Thus, the more prominent rightward asymmetry in superior temporal and inferior frontal cortices for males than for females suggests a sexual dimorphism in brain lateralization. MRI studies have shown that toddlers with ASD had higher gray and white matter in the superior temporal cortex than controls, and this abnormal growth was more pronounced for females than for males (Schumann et al. 2010). Thus, the laterality patterns of the FCD could be used to test if ASD is an extreme of the typical male profile, as suggested by the extreme brain theory of autism (Baron-Cohen 2003), and could serve as a biomarker for ASD. On the other hand, the leftward lateralization of the long-range FCD in inferior frontal cortex was significantly stronger for females than for males, which suggests greater lateralization for the language function in the female brain. Some have proposed that the male brain is more asymmetrical than the female brain (Shaywitz et al. 1995), and our findings support an overall greater lateralization of short-range connectivity for males. However, this was not the case for the long-range connectivity for which there was higher asymmetry in some regions for females (inferior frontal) and in others for males (superior temporal). Note that a more widespread pattern of gender differences in laterality may emerge in nonresting conditions (i.e., during cognitive, emotional, or perceptual stimulation tasks).
The 1000 functional connectomes database includes limited phenotypic characterization of the individuals. Thus, it was not possible to ascertain the functional significance of the gender effects on short- or long-range FCD. Nonetheless, the consistency of the findings from resting-state FCD patterns (Tomasi and Volkow 2010) makes it possible to generate standards that can be used in subsequent studies to compare with patient populations.
The FCD patterns showed a rightward asymmetry in temporal (short- and long-range) and cingulate cortices (long-range) and a leftward asymmetry in posterior occipital (short- and long-range) and inferior frontal (long-range) cortices and angular gyrus (long-range). The male brain was more rightward lateralized than the female brain. The lateralization of short-range connectivity was stronger for males than for females (rightward lateralized), whereas lateralization of long-range connectivity was stronger in some regions for females (leftward) and in others for males (rightward).
National Institutes of Alcohol Abuse and Alcoholism (2RO1AA09481).
Conflict of Interest: None declared.
PubMed Central Canada is a service of the Canadian Institutes of Health Research (CIHR) working in partnership with the National Research Council's national science library in cooperation with the National Center for Biotechnology Information at the U.S. National Library of Medicine(NCBI/NLM). It includes content provided to the PubMed Central International archive by participating publishers.


text:
"The length of our days is seventy years–or eighty if we have the strength . . . Teach us to number our days aright, that we may gain a heart of wisdom" (Ps. 90: 10, 12 NIV). It was once stated, "You can't teach an old dog new tricks." Well, I'm not so sure I can speak for the senior canines, but this 66 year-old grandma who entered the business world at age 59 is still learning new tricks every {Read More}
Thank you to today's guest blogger for sharing with us all!


text:
Create a Ning Network!
Beauty Made Easy!!
Deedee has not received any gifts yet
Give a Gift
Posted on May 3, 2009 at 7:45pm
Join DeziBeautyBabes
Welcome toDeziBeautyBabes
Sign Upor Sign In
© 2017 Created by Dezi.
Powered by
Report an Issue |
Terms of Service
Please check your browser settings or contact your system administrator.