a side-by-side reference sheet
grammar and invocation | variables and expressions | arithmetic and logic | strings | dates and time | arrays | arithmetic sequences | functions | execution control | file handles | processes and environment
fortran | apl | |
---|---|---|
version used |
GNU Fortran 4.5 (Fortran 95) | GNU APL 1.5 |
show version |
$ gfortran --version | $ apl --version |
grammar and invocation | ||
fortran | apl | |
hello word | $ cat hello.f95 program hello write(*,*) 'Hello, World!' end program hello $ gfortran hello.f95 $ ./a.out Hello, World! |
$ cat hello.apl "Hello, World!" )OFF $ apl --script --noSV -f hello.apl Hello, World! |
file suffixes source, header, object file |
.f95 none .o | |
block delimiters | program … end program function … end function subroutine …end subroutine if … then … elseif … then … else … endif do while … end do do … end do |
|
statement terminator | newline when a line ends with & the statement continues on the following line |
|
end-of-line comment | ! comment | ⍝ comment the standard name for ⍝ is "lamp" |
multiple line comment | none | |
variables and expressions | ||
fortran | apl | |
are identifiers case sensitive | no; Fortran 77 and earlier required all caps | yes |
variable types | integer real complex character logical | |
variable declaration | integer :: n real :: x = 3.7 ! variable declarations must appear before ! all other statements in a program or function body |
|
undeclared variable type | inferred from first letter of name: I-N: integer A-H, O-Z: real |
|
declare primitive type on stack | integer::i integer::j = 3 |
|
assignment | i = 3 | ⍝ leftarrow: ← i ← 3 |
null |
used for pointers only: null() |
|
undefined variable access | evaluate to 0 or 0.0, depending upon the first letter of the variable name | VALUE ERROR |
arithmetic and logic | ||
fortran | apl | |
boolean type |
logical | all values have same type |
true and false |
.true. .false. | 1 0 |
falsehoods |
.false. no implicit conversion of values to booleans |
0 0.0 |
logical operators | .and. .or. .not. | ⍝ and: ∧ ⍝ or: ∨ ⍝ not: ~ ∧ ∨ ~ |
relational operators |
== /= > < >= <= | ⍝ match: ≡ ⍝ unequal: ≠ ⍝ aft: ≥ ⍝ fore: ≤ ≡ ≠ > < ≥ ≤ |
min and max | min(1, 2, 3) max(1, 2, 3) |
⍝ minimum: ⌊ ⍝ maximum: ⌈ 1 ⌊ 2 ⌊ 3 1 ⌈ 2 ⌈ 3 ⌊ / 1 2 3 ⌈ / 1 2 3 |
integer type |
integer number of bytes can be specified: integer(kind=4) |
all values have same type |
integer literal | -4 | ⍝ macron: ¯ ¯4 |
float type | real double precision number of bytes can be specified: real(kind=4) |
all values have same type |
arithmetic operators |
+ - * / | ⍝ times: × ⍝ per: ÷ + - × ÷ |
integer division | 7 / 3 mod(7, 3) |
|
integer division by zero | real :: x = 0.0 integer :: i = 0 ! compiler error: 1.0 / 0.0 ! +Infinity: 1.0 / x ! floating point exception: 1 / i |
DOMAIN ERROR |
float division |
3 / float(7) | 3 ÷ 7 |
float division by zero | real :: x = 0.0 integer :: i = 0 ! compiler error: 1.0 / 0.0 ! +Infinity: 1.0 / x ! floating point exception: 1 / i |
DOMAIN ERROR |
power | 2.0 ** 3.0 | 2 * 32 |
sqrt | sqrt(2) | 2 * 0.5 |
sqrt -1 | real :: x = -1.0 complex :: z = (-1.0, 0.0) ! compiler error: sqrt(-1.0) ! NaN: sqrt(x) ! (0.000, 1.000) sqrt(z) |
⍝ 0J1: ¯1 * 0.5 |
transcendental functions | exp(2.0) log(2.0) log10(2.0) sin(2.0) cos(2.0) tan(2.0) asin(0.5) acos(0.5) atan(0.5) atan2(1.0, 2.0) |
⍝ log: ⍟ ⍝ circle: ○ * 2 ⍟ 2 10 ⍟ 2 1 ○ 2 2 ○ 2 3 ○ 2 ¯1 ○ 0.5 ¯2 ○ 0.5 ¯3 ○ 0.5 ?? |
transcendental constants e and pi |
exp(1.0) 2.0 * asin(1.0) |
* 1 ○ 1 |
float truncation truncate, round, ceiling, floor |
int(3.7) none ceiling(3.7) floor(3.7) |
?? ?? ⌈ 3.7 ⌊ 3.7 ⍝ ceiling: ⌈ ⍝ floor: ⌊ |
absolute value | abs(-7) abs(-7.77) |
| ¯7 | ¯7.77 |
complex type | complex uses 8 bytes: complex(kind=4) |
all values have same type |
complex construction | (0.0, 1.0) (0.0, 2.0) (0.0, 3.0) |
0J1 0J2 0J3 |
complex decomposition real and imaginary component, argument, absolute value, conjugate |
real(z) imag(z) atan2(imag(z), real(z)) abs(z) conjg(z) |
z ← 3J2 (z + + z) ÷ 2 | (z - + z) ÷ 2 ?? | z + z |
random number | real r ! random float from 0.0 to 1.0: call random_number(r) |
⍝ random integer from 1 to 100: ? 100 |
random seed | integer n integer, allocatable :: seed(:) call random_seed(size=n) allocate(seed(n)) do i = 1, n seed(i) = i + 2 end do call random_seed(put=seed) |
⎕RL ← 17 |
bit operators | right shift if pos is positive: ishft(i, pos) iand(i, j) ior(i, j) ieor(i, j) not(i) |
|
strings | ||
fortran | apl | |
string type |
characater(len=100) s | |
string literal |
'don''t say "no"' "don't say ""no""" |
'don''t say "no"' |
newline in string literal | "lorem" // achar(10) // "ipsum" | |
string escapes | none | |
convert string to numeric | ⍝ execute: ⍎ ⍎ '4' |
|
convert numeric to string | ||
split | none | |
join |
, / 'foo' 'bar' 'baz' | |
concatenate | 'hello' // ' world' | 'hello' , ' world' |
replicate | character(len=80) :: hbar hbar = repeat('-', 80) |
|
substring | "hello"(1:4) | |
index | counts from one, returns zero if not found index("hello", "el") |
|
sprintf | character(len=100) :: s write(s,'(A A F9.3 I9)') 'foo', ':', 2.2, 7 |
|
uppercase | none | |
lowercase | none | |
trim | ?? adjustl(' foo') trim('foo ') |
|
length |
len("hello") | ⍴ 'hello' |
character access | "hello"(1:1) | |
chr and ord | achar(65) iachar('A') |
|
dates and time | ||
fortran | apl | |
current local date and time | integer dt(8) ! yyyy, mm, dd, utf_offset_min, hh24, mi, ss, ms call date_and_time(values=dt) |
⍝ array of 7 integers: yyyy, mm, dd, hh24, mi, ss, ms ⎕TS |
sleep | ! gnu extension; sleep 10s: call sleep(10) |
none |
cpu usage | real t1, t2 call cpu_time(t1) … call cpu_time(t2) write(*, *) 'elapsed time: ', t2 - t1 |
none |
arrays | ||
fortran | apl | |
allocate on stack | ! uninitialized values get zero values: integer, dimension(3) :: a integer :: a2(3) |
none |
allocate on heap | ! unitialized values get zero values: integer, dimension(:), allocatable :: a allocate(a(3)) |
all data is stored on heap |
free heap | ! usually not necessary, since memory is freed ! when the variable goes out of scope. deallocate(a) |
none; memory is garbage collected |
literal | integer::a(3) = (/ 1, 2, 3 /) | a ← 1 2 3 |
size |
size((/ 1, 2, 3 /)) | ⍝ rho: ⍴ ⍴ a |
lookup |
! indices start at one integer :: a(4) a = (/ 7, 8, 9, 10 /) a(2) |
a ← 7 8 9 10 a[2] (7 8 9 10)[2] ⍝ change index origin from 1 to 0: ⎕IO ← 0 |
update | a(1) = 8 | a[1] ← 8 |
out-of-bounds behavior | If the array dimensions are set at compilation time (i.e. the array is stack allocated), then the code fails to compile. Out-of-bounds references to arrays with dimensions set at run time (i.e. the array is heap allocated) could segfault or return a memory value outside of the array. |
INDEX ERROR |
element index | ⍝ evaluates to 2: 7 8 9 ⍳ 8 |
|
slice | ! can't slice literal int::a1(3),a2(2) a1 = (/1,2,3/) a2 = a1(1:2) |
⍝ 7 8: a ← 7 8 9 10 1 ↓ 3 ↑ a |
slice to end | ⍝ 8 9 10: a ← 7 8 9 10 1 ↓ a |
|
manipulate back | a ← 7 8 9 10 ⍝ 10: ¯1 ↑ a ⍝ set a to 7 8 9: a ← ¯1 ↓ a ⍝ set a to 7 8 9 11: a ← a , 11 |
|
manipulate front | a ← 7 8 9 10 ⍝ 6: 1 ↑ a ⍝ set a to 8 9 10: a ← 1 ↓ a ⍝ set a to 6 8 9 10: a ← 6 , a |
|
concatenate | 1 2 3 , 4 5 6 | |
replicate | ⍝ 10 zeros: 10 / 0 |
|
copy | a ← 1 2 3 b ← a ⍝ does not modify a: b[1] ← 4 |
|
iterate | ||
sort | a ← 8 7 10 9 a[⍋ a] |
|
reduce | + / 1 2 3 ⍝ 2: - / 1 2 3 |
|
arithmetic sequences | ||
fortran | apl | |
unit difference | ⍝ iota: ⍳ ⍳ 100 |
|
difference of 10 | ⍝ 0, 10, ..., 100: 10 × ( ⍳ 11 ) - 1 |
|
difference of .1 | ⍝ 0.0, 0.1, ..., 10.0 .1 × ( ⍳ 101 ) - 1 |
|
functions | ||
fortran | apl | |
define function | integer function add(n, m) integer, intent(in) :: n integer, intent(in) :: m add = n + m end function add |
⍝ define dyadic operator: ∇r ← a add b r ← a + b ∇ ⍝ define monadic operator: ∇r ← double n r ← 2 × n ∇ |
invoke function |
add(3, 7) | 3 add 7 double 7 |
forward declaration of function | ||
overload function | ||
nest function | ||
missing argument behavior | set to zero | |
extra argument behavior | ignored | |
default value for parameter | real function mylog(x, base) real :: x real, optional :: base if (present(base)) then mylog = log(x) / log(base) else mylog = log(x) / log(10.0) endif end function mylog |
|
variable number of arguments | none | |
named parameters | ||
pass by value | ||
pass by address | ||
pass by reference | ||
return value | assign to implicit variable with same name as function; can use return statement to terminate function execution | |
no return value | ||
multiple return values | ||
named return values | ||
anonymous function literal | none | |
function with private state | ||
function as value | none; function pointers added in Fortran 2003 | |
execution control | ||
fortran | apl | |
for | do n = 1, 10, 1 write(*,*) n end do |
|
if | if (n == 0) then write(*,*) 'no hits' elseif (n == 1) then write(*,*) 'one hit' else write(*,*) n, 'hits' endif |
|
while | n = 1 do while ( n < 10 ) write(*,*) n n = n + 1 end do |
|
switch | ||
break/continue |
exit cycle | |
file handles | ||
fortran | apl | |
standard file handles | ! common unit identifiers for stdin, stdout, and stderr: 5 6 0 |
|
read line from stdin | character(len=100) line read(*, fmt="(a)") line |
|
write line to stdout | write(*, *) 'Hello, World!' | |
write formatted string to stdout |
write(6, fmt="('count: ', i7)") 7 | |
open file for reading | ! the 'unit' integer is the file descriptor. Use an unused ! number. The standard file handles 0, 5, and 6 are already taken. open(unit=7, file='/etc/passwd', action='read') |
|
open file for writing | open(unit=7, file='/tmp/foo.txt', action='write') | |
close file | close(7) | |
i/o errors | ||
read line | ||
iterate over file by line | ||
read file into array of strings | ||
read file into string | ||
write string | ||
write line | ||
flush file handle | ||
end-of-file test |
||
get and set file handle position | ||
open unused file | ||
processes and environment | ||
fortran | apl | |
command line arguments | character(len=10) :: arg integer arg_len i = 1 do while (i <= command_argument_count()) call get_command_argument(i, arg, arg_len) if (arg_len > 10) then write(*,*) 'truncated argument: ', arg else write(*,*) 'full argument: ', arg endif i = i + 1 end do |
⎕ARG |
environment variable | character(len=100) :: var integer var_len call get_environment_variable('HOME', var, var_len) if (var_len > 100) then write(*,*) 'truncated env var: ', var else write(*,*) 'full env var: ', var endif |
⍝ quad: ⎕ ⎕ENV 'HOME' ⍝ returns n by 2 array containing all environment ⍝ variable names and their values: ⎕ENV '' |
exit | stop ! nonzero status: error stop 1 |
)OFF |
vectors | ||
fortran | apl | |
vector literal | same as array | ⍝ same as array: 1 2 3 |
element-wise arithmetic operators | + - * / | + - × ÷ |
result of vector length mismatch | compilation error | LENGTH ERROR |
scalar multiplication | 3 * (/1,2,3/) (/1,2,3/) * 3 |
3 × 1 2 3 1 2 3 × 3 |
dot product | dot_product((/1,1,1/),(/2,2,2/)) | 1 1 1 + . × 2 2 2 |
matrices | ||
fortran | apl | |
matrix literal or constructor | ! column-major order: integer::A(2,2) = & reshape((/ 1, 3, 2, 4 /), & (/ 2, 2 /)) integer::B(2,2) = & reshape((/ 4, 2, 3, 1 /), & (/ 2, 2 /)) |
⍝ row-major order: A ← 2 2 ⍴ 1 2 3 4 |
constant matrices all zeros, all ones |
3 3 ⍴ 0 3 3 ⍴ 1 |
|
diagonal matrices and identity |
⍝ 3×3 identity: I ← 3 3 ⍴ 1 , 3 ⍴ 0 D ← I + . × 1 2 3 |
|
dimensions | A ← 2 3 ⍴ 1 2 3 4 5 6 ⍴ A |
|
element access | A ← 2 2 ⍴ 1 2 3 4 ⍝ 1: A[1; 1] |
|
row access | A ← 2 2 ⍴ 1 2 3 4 ⍝ 1 2: A[1; ] |
|
column access | A ← 2 2 ⍴ 1 2 3 4 ⍝ 1 3: A[; 1] |
|
scalar multiplication | A ← 2 2 ⍴ 1 2 3 4 3 × A A × 3 |
|
element-wise operators | + - × ÷ | |
transpose | A ← 2 2 ⍴ 1 2 3 4 ⍝ cant: ⍉ ⍉ A |
|
multiplication | matmul(A, B) | A ← 2 2 ⍴ 1 2 3 4 B ← 2 2 ⍴ 4 3 2 1 A + . × B |
inverse | A ← 2 2 ⍴ 1 2 3 4 gray|⍝ inverse: ⌹## ⌹ A |
|
____________________________________________________________________________________________________ | ____________________________________________________________________________________________________ |
Grammar and Invocation
file suffixes
The suffixes used for source files, header files, and compiled object files.
fortran:
The gfortran compiler will treat files with .f and .f77 suffixes as the older fixed format source code, and it will treat files with .f90 and .f95 suffixes as free format source code conforming to the 1990 and 1995 Fortran standards.
Traditionally Fortran does not have header files. The Fortran 90 standard introduced modules. To support the feature the compiler will generate .mod files whenever a source file with a module definition is encountered. They contain type declarations like C headers, but unlike C headers they are not intended to be edited by people.
block delimiters
fortran:
The list of keywords is not exhaustive.
Variables and Expressions
undeclared variable type
fortran:
This makes undeclared variables starting with 'q' integers:
implicit integer q
undefined variable access
fortran:
It is possible to require that all variables are declared:
implicit none
Variable which are declared but not initialized are assigned zero values.
Arithmetic and Logic
boolean type
The boolean type.
true and false
The literals for true and false.
falsehoods
Values which are false in a boolean context.
logical operators
The logical operators for conjunction, disjunction, and negation.
fortran:
.eqv. .neqv.
apl:
APL also has operators for "nand" and "nor":
⍲ ⍱
relational operators
min and max
integer type
integer literal
The syntax for integer literals.
apl:
The minus sign can be used as a unary operator, but applies to the entire array. The following expressions are the same:
- 4 5 6
¯4 ¯5 ¯6
unsigned integer type
Strings
sprintf
fortran:
Fortran format strings use these expressions:
A | character |
Dwidth.precision | double in scientific notation |
Ewidth.precision | real in scientific notation |
Fwidth.precision | real in fixed point notation |
Iwidth | integer |
X | space |
nX | repeat following format expression n times |
/ | newline |
width and precision are integers. width is the field width in characters. Other characters in the format string are ignored.
Dates and Time
current local date and time
sleep
cpu usage
Arrays
Arithmetic Sequences
unit difference
difference of 10
difference of 0.1
Functions
Execution Control
break/continue
fortran:
Fortran has a continue statement which is a no-op statement used as a target for goto statements.
Here is an example of using exit to terminate what would otherwise be an infinite loop:
n = 1
do
if (n > 10) exit
write(*, *) n
n = n + 1
end do
Labels can be provided for nested do loops. The labels can be provided as arguments to exit and cycle:
foo: do
bar: do n = 1, 10, 1
write(*,*) n
exit foo
end do bar
end do foo
File Handles
standard file handles
The file handles for standard input, standard output, and standard error.
fortran:
Fortran uses integers which it calls unit identifiers for file descriptors. The unit descriptors 5, 6, and 0 are often but not always used for stdin, stdout, and stderr.
Unit descriptors are provided as the first argument to read and write. If the first argument of read is an asterisk, it will use stdin. If the first argument of write is an asterisk, it will use stdout.
write formatted string to stdout
How to print a formatted string to standard out.
fortran:
Notation used in Fortran format strings.
Processes and Environment
Vectors
Matrices
Fortran
The GNU Fortran Compiler
Fortran 77 Tutorial
Fortran 90 Tutorial
Fortran Standards Documents
BLAS: A Quick Reference Guide (pdf)
Modern Fortran compilers support two source code formats: the traditional fixed format and the free format introduced with Fortran 90.
If a Fortran source file has a .f suffix, the gfortran compiler expects the code to have fixed format. If the suffix is .f90 or .f95 it expects free format code.
Here is an example of fixed format code:
C Hello World
* in Fortran 77
program hello
10000 write(*,*) 'Hello,'
+ , ' World!'
end program hello
This first column can contain a 'C', 'c', or '*' to indicate the line is a comment.
Columns 1 through 5 can contain an optional statement label. A statement label consists of digits. The statement label may contain leading zeros which are ignored. A statement label cannot consist entirely of zeros.
If column 6 contains a non-space character and columns 1 through 5 are blank, then the line is treated as a continuation of the previous line. The continuation character is not itself part of the statement, so any non-space character can be used, but '+' is a common choice.
Columns 7 through 72 contain the statement.
Columns 73 through 80 can contain optional sequence numbers. They were formerly used to help keep punch cards in the correct order.
Here is an example of free format code:
! Hello World in Fortran 90
program hello
write(*,*) 'Hello,' &
, ' World!'
end program hello
There are no special columns in free format code. There is no limit on the length of lines or statements. If it is desirable to split a statement up over multiple lines, the '&' character can be used to indicate the statement continues on the following line.
APL
A Dictionary of APL
A Programming Language
The first issue one must resolve when getting started with APL is figuring out how to enter the special characters.
One technique is to add a input method to your desktop environment. Here are APL input methods for Mac OS X and Windows. The Windows input method uses AutoHotkey. If you don't have AutoHotkey installed, you can use the .exe file that was generated using AutoHotkey. Otherwise you can use the .ahk file.
The notation in the above input methods is derived from the standard names and synonyms for the symbols in the APL community. The standard name for ⍋ is "grade". The above input methods use an ampersand prefix in front of the standard name. Thus, to create a ⍋ character, one types "@grade" when the input method is in effect.