text:
User:Davjam2/Numbers

Quite a bit is said about numbers in the Type basics II and Classes and types pages. Those pages use the numeric types and classes in Haskell to illustrate the Haskell type system. This page is more focussed on numbers themselves: how to do different types of numeric computations using the Haskell types and classes.

Numbers

Mathematically, numbers can be classified into different sets, such as the integers ($$\mathbb{Z}$$), the rational numbers ($$\mathbb{Q}$$) and the real numbers ($$\mathbb{R}$$). It is common to say that the integers are a subset of the rational numbers, and that the rational number 5 "is an integer". Some operations, such as division, are only possible within certain sets of numbers: there is no solution to $$2x=5$$ amongst the integers, but there is amongst the rational numbers. Rational numbers are said to be closed under division (excluding division by zero), but integers are not.

No programming language (not even Haskell) has a way of representing "any number". Generally, a language will have different numeric types, each representing (possibly a subset of) the numbers in one of the classification sets. In Haskell, there are types such as,   and   that closely represent $$\mathbb{Z}$$, $$\mathbb{Q}$$ and a subset of $$\mathbb{R}$$. Prelude provides a number of these types, and more are available in other modules. None of these types is perfect in all situations: for example, none of the standard types can represent $$\sqrt{2}$$ or $$\pi$$ precisely.

In Haskell, the  and   are definitely not the same thing. It's not even possible to compare them directly using, since   can only compare values of the same type. Many programming languages allow operations on numbers of different types (such as adding the integer 5 to the number 3.14). They usually do this by quietly "upgrading" one of the numbers so that they are both of the same types before applying the operation. Haskell does not directly allow addition of different types of number, nor does it quietly "upgrade" numbers to different types. It does, however, allow explicit conversion between types.

Most standard numeric operations are defined as class methods, so that they work on all of the relevant numeric types. For example:  (addition) is defined to work on all numeric types;   (division, which can find the solution to $$2x=5$$) is not available for integer types; and   (finding the sine of an angle) will work on types representing (as well as they can) real numbers. A smaller number of mathematical operations (e.g. ) are defined as functions (which call the class methods). Many of the numerical functions (class methods or not) are partial, and will throw exceptions for certain parameters (for example division by zero, for some types). You should either ensure your code avoids such parameters, or handles the exceptions that may occur.

Numeric Types
Some of the Haskell numeric types are:

The set shown against a type is the "smallest" of those sets illustrated above that contains all of the numeric values of that type. The types,   and   can represent all of the values in the corresponding sets, subject to the computer's memory and performance limits. The other types can represent only subsets of the corresponding sets, for example  can only represent integers in the range -128 to 127, and   can only represent those real numbers within the (approximate) range –3.4028235 × 1038 to –3.4028235 × 1038 that can be written with about 8 significant digits.

In mathematics, any value in a "smaller" set has an equivalent in a "larger" set. For example, $$\mathbb{Z} \subset \mathbb{R}$$, and all integers have an equivalent real number. In Haskell types, this relationship is only partially preserved:  has an equivalent , but   does not have a corresponding value of type   (since   does not represent all real numbers).

The $$^+$$ indicates types that include values (such as "infinity" and "negative zero") in addition to those in the corresponding sets.

A blank in the Module column means the type is exported by Prelude.

Some of the numeric types ( and  ) are parametized types, i.e. you can't create a value of type , but you can create a value of type  ,  , etc.

There are some type-specific functions, for example, which returns the numerator of a.

There are many more numeric types than listed in the table above, and the set of numeric types can be extended:
 * you can create your own―something we will do later in this page; and
 * you can search Hoogle for other libraries that provide types such as matrices, polynomials, etc.

What Numeric Means (The Class)
By "numeric", we mean that the types support some basic maths such as addition and multiplication. In Haskell, these basic maths operations are defined in the  class. The types listed above all are instances of, and each provides an appropriate implementation for them.

Note the type of the addition operator:

As explained previously, this type signature shows that  is a function that takes two parameters (of the same type), and returns a value (of that same type). But the type can't be any of type (it can't be a, for example), it has to be a type that's an instance of the class. Hence  is polymorphic: it can operate on different types (at different times; not in the same expression), subject to the   constraint. (We will talk about how to calculate the sum of numbers of different types in the section on numeric conversions later.)

also includes functions for multiplication and subtraction (and some more; we will see the details later). It does not provide division. There are additional numeric classes that provide functions that are only suitable for a subset of the numeric types, for example:
 * , which returns the sine of an angle, where it doesn't make sense to return any of the integral types; and
 * and, which do different types of division suitable for different types of number.

also includes the function, which creates a value of any numeric type from an integer (e.g.   gives  ). This is one of a number of type conversion functions discussed in more detail later. It is also used by the Haskell when compiling a numeric literal.

All of the numeric types above are instances of, though this should be used with care with types representing approximations (e.g.  ). Many are also instances of other standard classes ( ,   and  ), but there are nuances in their behaviour.

Accuracy and Precision
Some of these types (e.g. ) offer complete accuracy. You can multiply two 50-digit  values together and get a mathematically exact 100-digit result. is also completely accurate.

Some of the types (e.g.,  ) are completely accurate, provided the numbers stay within the range supported by the type. (Note that operations that cause overflow typically don't raise exceptions).

Some types (e.g.  and  ) are used for recording approximations. offers greater precision that, but neither can represent the exact value of $$\pi$$, for example. They also suffer from rounding errors, e.g:

As a result, for approximation types:
 * it probably makes sense to round values as required prior to display to a user (i.e. don't use the result of ); and
 * it probably doesn't make sense to compare them for equality.

Overflow
In general, mathematical operations in Haskell do not raise overflow exceptions. The actual behaviour differs amongst the types.

''TODO: Fix the statements about modulo behaviour for integral types since they may not be correct. The Haskell report says the overflow behaviour is undefined, and it is possible that it is different in different implementations (e.g. on LLVM).''

For bounded integral types, values "wrap" (i.e. the arithmetic is performed modulo 2n, where n is the number of bits in the type):

If overflow is likely, you should consider the options, for example:
 * use a different type (e.g.  instead of , where overflow is not possible); or
 * if a different type is not possible (e.g. it's an integer that needs to be stored in some fixed size field in a database), maybe use a numeric type from a library that does raise exceptions on overflow (or use e.g.  but do validation prior to trying to store the result); or
 * be happy that it's what you wanted (e.g. for calculating a checksum of a file).

Note that  does raise an exception for a bounded integral type when exceeding a bound:

can raise an exception during subtraction:

When floating point types overflow, they take the value :

Division by Zero
Division by zero will raise an exception for some types, but for  and , a value   is returned:

However, it is possible to create  values with zero denominators by directly using the   constructor or utility functions:

Note that  and   also support negative infinity, negative zero, and NaN ("not a number"):

They will also return  for e.g..

They support functions  and   so you can check for potential errors.

Enumerations
Many of the numeric types are instances of, including fractional types. The  class includes methods   and   for converting between values of the type and values of the (bounded) type. Most types (including most numeric types) will not have a 1:1 mapping with, leading to some interesting behaviour.

There is no requirement that  represents the numeric value n, though this is the case for many types:

In some cases where n is out of bounds,  will cause "wrapping" but   will raise an exception:

will have corresponding behaviour, and in some cases it truncates fractional parts:

Where the result is out of bounds for an, typically "wrapping" will occur without raising exceptions:

and  are consistent with the above. In many cases,  has the same effect as adding 1 (but not for   etc). As mentioned above,  may raise an exception when exceeding the bounds of a type. For some types  will work correctly even though   "wraps":

For imprecise floating-point types,  will make no difference to large values due to lost precision:

also includes methods  and variations. Haskell compiles,  , etc, into these.

Internal Representation
Most numeric types provide functions that give access to their internal representations.

Some numeric types are made of separate components, for example  has two   components, and   has two   components. Both types have functions e.g.  or , that access these.

exposes its infix constructor, which can be used for creating complex numbers, pattern matching, etc. does not expose its constructor (it's, hidden in  ). is not a constructor, it's an operator that first reduces the ratio (e.g. $$\tfrac{3}{12}$$ to $$\tfrac{1}{4}$$) and then creates the Ratio. In addition, the  method displays.

The bits representation of integers can be accessed via  module, for example:

There are also functions such as  for accessing details of floating point numbers.

Type Classes
As stated above, most standard numeric operations are defined as class methods, so that they can be applied to all appropriate types. The numeric type classes in Prelude are:

The classes form a hierarchy (shown here), so that a type can't be an instance of, say  if it's not also an instance of.

Introduction
Suppose we want a function that can add any  value to $$\pi$$. Let's try:

Oops - we get an error:. This makes sense: the definition of  requires both types to be the same.

How do we fix this? Using the  method on the   class:

is one of a number of numeric conversion functions that we'll look at.

However, before looking at them, note that there aren't separate,  ,  , etc, functions. Instead,  is a method on the class , and each instance provides its own implementation. When  is called, the function that calls it needs to be clear which type should be returned. In the above example, the required type was determined by type inference, based on the types of  and.

More Integral Conversions

The diagram on the right shows  in a class hierarchy diagram, along with a number of other conversion functions. It is a method on the  class, so can create a value of any numeric type from a   value.

Another method shown is. This is a method on the  class, so any   type (e.g. ,  , and even   itself) provides a method to create an   with the equivalent numeric value. Prelude also includes a function  that combines   and , making it easy to convert from any   type to any numeric type.

Fractional Conversions
Two class methods support the majority of fractional conversions:

is a method of the  class, so it's possible to create a   of any type from a. As with, the function that calls   needs to be clear what type should be returned.

Just as with, we have a type problem if we try to write this:

since we're trying to add a  to a.

is a method of the  class, so will work for e.g. ,  ,  , etc, and even on   itself. Each type instance will define its own implementation, and is expected to return "the rational equivalent of its real argument with full precision". For approximate types (e.g. ) the result should therefore be an exact equivalent of the approximate value.

There is also the function, that is a combination of   and  , which can convert any instance of   to any instance of.

Note that, with  and ,   loses the negative of negative zeros and "rounds" infinities to large fractions. This impacts how  handles conversions between them. The functions  and   in   avoid these problems:

Rounding
(and hence ) will not work on, say, , since there is no way to return a value equivalent to   as an. However, there are functions such as,  , etc. These are methods on the   class that will return a value of any   type:

Since there's no integer that's a numeric equivalent of, these functions give different options for the conversion:

also provides the method, which decomposes a number into an integral and fractional parts, e.g:

, etc, and generic versions
Prelude includes functions such as  and   that return or take values only of type. You may think "well, I'd never need to use a huge number such as available in, so   is good enough." But remember there are other  types as well, such as , etc, and it might sometimes be useful to get/give those as parameters.

Hence the module  also exports "generic" versions of the functions:

Note that  can return any , although it will always return a value equivalent to an integer (e.g.  ).

Converting to/from Strings
There are a number of functions for converting numbers between numbers and strings. and  are some, but they only provide limited behaviour and may well not be adequate for many purposes.

Some other functions include  (which can show an integer value in any base), and   (which has an option to specify the number of decimal places). These functions return a type, which makes them more efficient when building large strings.

There is also the function  in the   module which can make it easier to embed formatted numbers within longer strings, for example:

Beware that  can't check that the parameter types against the format string at compile time, and will raise a run-time exception if they mismatch.

Operators, Sections
Many mathematical functions are operators, which are often written in infix notation, e.g., but can be written prefix, e.g.  . Non-operator functions are often written in prefix, e.g.  , but can be written infix, e.g..

Operators can be used in sections, e.g., which is equal to  , and  , which is equal to. Functions written in infix can also be used as sections, e.g.  or.

Fixity, Precedence
What is meant by the mathematical expression 5 + 32 × 4? There is a convention that we apply the operations in a certain order, like this: 5 + 32 × 4 = 5 + 9 × 4 = 5 + 36 = 41. The convention says that the exponentiation (raising to a power) operator has a higher precedence than multiplication, which in turn has a higher precedence than addition. If we wanted to add the 5 and 3 together first, we'd indicate it using brackets: (5 + 3)2 × 4 = 82 × 4 = 64 × 4 = 256.

What about the expression 7 − 3 − 2? The convention is that subtraction associates to the left, like this: 7 − 3 − 2 = 4 − 2 = 2. . If we wanted the 3 − 2 to happen first, we'd also need to indicate it using brackets: 7 − (3 − 2) = 7 − 1 = 6.

Haskell is aware of the conventions and the use of brackets:

In a Haskell program, the precedence and associativity of operators can be specified using "fixity" declarations. For example,  and   have these declarations:

This shows that  has a higher precedence than , that   associates to the left and that   associates to the right. The standard mathematical operators follow the standard conventions, and are part of a precedence hierarchy that includes other operators, as shown here.

Fixity declarations can also be given for functions, and are used when those functions are written in infix style, e.g.:

Hence  means the same as.

Note that prefix function application has the highest precedence, so  means , not.

(negate) infix and prefix
The  operator can be used normally as an infix operator. However, uniquely, it can also be used as an (unbracketed) prefix operator, where it has the same meaning as. This can be very useful, but can also be a bit confusing at times.

These expressions are OK, and  has the two-parameter subtraction meaning:
 * (normal infix operator, giving 3)
 * (normal prefix operator, giving 3)
 * (normal section, means ).
 * (means )
 * (means )

These expressions are OK, and  has the one-parameter   meaning:
 * (means, since   has a higher precedence than  )
 * (means )
 * (means ).
 * (means ).
 * (means )
 * (means )

These are not OK:
 * and . These don't compile, since the negate operator has lower (or the same) precedence as the other operator.
 * . This means, since function application has highest precedence, which doesn't compile.
 * . Due the the special  prefix operator,   is not treated as a section. Instead it's interpreted as , which is not a function (and so can't be passed to  ). However, you can use the   function instead:   which gives.

Note that removing spaces makes no difference. For example  fails in exactly the same way as , despite it being "obvious to everyone that it should mean  ".

You may want to put brackets around any usage of  as a prefix operator for clarity. (And your own sanity).

Integer Literals
Suppose we want to define a  variable with the value $$1+\pi$$. We can do this:

OK, it only gives an approximation, but it's otherwise brilliant:

But how does this work? Why don't we get a type error? is defined to return a. So  must return a. So each of the parameters to  must be a. is defined so it can be a value of any instance of, one of which is  , so it's happy. however looks like an integer, which is not a, so how does that work?

The answer is that the  actually compiles to , so   is essentially:

is has type signature:

which can create a value of any numeric type we want. And right now we want a  (so we can add it to another   giving a  ), so that's what we get.

We can see the effect of the usage of  here:

So now we see why a simple number (e.g. ) has the weird type : because it can be any type of number you want it to be.

If you do the  exercise below, you should have created a   implementation for , so can do:

Note that just because Haskell can interpret a numeric literal in code, doesn't mean  will interpret it in the same way (or at all):

Although it can if you also implement a  instance.

Fractional Literals
Numeric literals containing decimal points or the  symbol are compiled using , so you can write:

where 0.5 "looks like" a floating-point number, but means effectively:

where the decimal number 0.5 has been converted to $$\tfrac{1}{2}$$ and wrapped with. We can see the effect of  here:

Note that to be a fractional literal, digits are needed both before and after the decimal point. (i.e.  not  ).

Literals in exponent form are compiled using, even if they don't contain a decimal point, and even if they are integer values:

GHC has a language extension  that allows can allows.

Negative Literals
A "negative literal" compiles to an application of the prefix  operator. Hence  is equivalent to , and   is equivalent to.

In some cases, brackets may be needed due to operator precedence. For example  doesn't compile, but   does. and  also compile correctly.

GHC has a language extension  that changes the interpretation, so that   is equivalent to.

Pattern Matching
Pattern matching on literals (numeric, character or string) compiles into a use of, so also depends on the numeric type being an instance of. E.g:

compiles to:

Note that the following compiles without warning, but will never return 2:

Non-Decimal literals
It is also possible to type integer literals in octal or hexadecimal:

which are also all compiled using.

Fractional literals must be in decimal, but GHC has a language extension  that also allows them in hexadecimal. is then the same as.

Type Ambiguity
In some cases there is ambiguity in the type of an expression. In many cases, ambiguous expressions will not compile, for example:

without the type signature is an error. You could want a, an  , an  , but how does the compiler know?

To fix this, you can specify the type (ideally give  a type signature), or add an expression that uses   and requires it to be a specify type, e.g:

This expression would fix  to have type. (Alternatively I could write e.g., which would require   to have type  . But I can't have both expressions, since   can only have one type.)

In some cases, it's not possible to fix ambiguity using a top-level type signature. For example:

Here I've given  a type signature, but it's still ambiguous what types   should create. Here's one way to fix it :

These examples above are fairly contrived to make a point. But the problem does often arise, especially with numeric types. For example:

which takes a, and returns   if it's closer to an even number than an odd number.

Note the types:

Hence  can produce any   type and   can consume any   type. How is the compiler meant to know which of the many  types to use? And why don't we get a type ambiguity error? The answer is defaults.

Each module (file) can have a  code declaration, and if it's omitted it's assumed to be:

The details of exactly how it works are specified in the Haskell Report, but essentially means that instead of giving an error for some ambiguous types, it will use one of the defaults if possible. It will use  for ambiguous   types and   for ambiguous   types. Hence  will compile so that   will produce, and   will consume, a value of type.

If you turn on e.g., which I often do, you will get a warning when type defaulting occurs.

You can change the defaulting rules by adding your own  statement to the .hs file. You can even disable it by stating, in which case   would give an error.

Note that  (hence also  ) and   (hence also  ) are often subject to defaulting, since (by design) they can return a value of any one of a number of types. As a result, numeric literals (which compile using  or  ) are also often subject to defaulting.

default in GHCi
It is a little curious that, when you enter e.g.  into GHCi, it replies with. Observe:

We can see that GHCi is being as helpful as possible. It does the sum initially using the default type because we didn't tell it otherwise (and displaying 135 is probably more helpful than displaying a type ambiguity error). If, however, we specify a type, it will do the calculation using the requested type, which in this case results in a different value.

Also, when we ask it to tell us the type of an expression, it will do so without regard to any defaulting that might occur upon evaluation.

We can turn off defaulting in GHCi as in .hs files:

In standard Haskell 2010, defaulting (and the  statement) only applies to numeric types. GHC (since 6.8.1) supports a language extension  that allows defaulting of additional types. You can enable this in .hs files, but it is initially enabled when you start GHCi:

where the type has defaulted to (the type).

You can modify this behaviour by turning off :

Mathematical Operations
Most mathematical operations in Haskell attempt to mirror "true" mathematical operations. However, none of the operations match perfectly due to overflow, rounding, etc, with different behaviours for different types. In addition, the standard types  and   represent real numerical values (within some range and only to certain precision), but also include representations of positive and negative infinities and negative zero.

This section compares Haskell mathematical operators and "true" maths.

TODO: Add something on benefit of Infinities, e.g. in

Addition, Subtraction and Multiplication
, (binary)  and   follow the mathematical operations of addition, multiplication and subtraction, subject to overflow and rounding. These operations are defined as methods of the  class, and are available for all numeric types. However, they are not closed for all types, for example  is not closed for the   type.

determines the additive inverse, where there is one.

Negative zeros and infinities behave "reasonably", for example:

From a Haskell syntax perspective,  can be used as a prefix operator to represent   (and so can't be used as a section with the operator on the left). There is a function, where   means "subtract 2 from 5", which can be used instead.

Division
Mathematically, integers are not not closed under division, but other numbers (rational, real, complex) are. Accordingly, Haskell splits division between two classes:
 * , which defines methods  and   (and the combined  ) for performing division with remainder (i.e. given integers $$a$$ and $$b$$, find integers $$q$$ and $$r$$ such that $$a = bq + r$$ and $$0 \le r < |b|$$).
 * , which defines method  for performing division without remainder (i.e. given $$a$$ and $$b$$, find $$q$$ such that $$a = bq$$). It also provides   for finding the multiplicative inverse.

provides two sets of "division with remainder" functions, illustrated here when dividing -11 by 4:

In mathematics there is no ability to divide by zero. In Haskell, division by zero is treated differently for different types:

However, note that these behaviours are not stated requirements of the  or   class methods. It would be possible for some  types (hand-written, or from other libraries) to return values, or for some   types to raise exceptions.

Exponentiation
Interestingly, Haskell has four different functions corresponding to exponentiation ("raising to a power"):

can also be used for floating-point types. gives $$x.r^n$$ where  is the   (often 2) of x.

,,  and
These are all functions that operate on  types, and call methods defined on the   class.

Each integer is either even or odd. returns a  indicating whether the argument is even, and   returns a   indicating whether the argument is odd.

calculates the greatest common divisor of two integers, using the Euclidean algorithm. For example,  = 4.

uses  to calculate the lowest common multiple. For example,  = 24.

and

determines the absolute value of x, often written $$\vert x \vert$$. determines the sign of x.

Both operations are are methods of the  class and are available for all numeric types. The two functions adhere to the law that, for any number x, $\equiv x$. For all standard numeric types,  returns a value of "magnitude" 0 or 1, but this is not a general requirement.

For any real number x: $$\equiv x$$ if $$x \ge 0$$ and  $$\equiv -x$$ if $$x < 0$$; and   is 1, 0 or -1. For types that support negative zero,  gives.

For a (non-zero) complex number x:  is a complex number with magnitude 1 and the same phase as x; and   is a the magnitude of x (as a complex number with imaginary part of 0). Hence if $$x = re^{i\theta}$$, then $$\equiv e^{i\theta}$$ and  $$\equiv r+0i$$

Irrational and Transcendental Functions
These functions all operate on instances of the  type, on either real or (with the exception of  ) complex numbers. There are a number of subtleties around their use:

 * precision: these functions produce only approximations to the mathematical results. For example, mathematically $$\sin(-\pi)=0$$, but GHC calculates to be.
 * principle values: mathematically, some "functions", especially "inverse" functions, are multivalued. For example, $$x \to x^2$$ maps both $$2$$ and $$-2$$ to $$4$$. The inverse function $$x \to \pm\sqrt{x}$$ maps $$4$$ to both $$2$$ and $$-2$$. Similarly $$x \to \cos x$$, which is periodic, maps $$0$$, $$2\pi$$ and $$4\pi$$ (and infinitely many other values) to $$1$$. The inverse function maps $$1$$ back to those infinitely many values. Sometimes only a single result is desired and, by convention, the notation $$\sqrt{x}$$ usually means only the positive value. Depending on context, $$\arccos x$$ may also refer to only a single principle value. The Haskell functions  and   only return a principle value for any given input:   gives   and   gives  . These principle values are somewhat (but no universally) standardised. In some cases, for example $$x \to \log_e x$$ (the inverse of $$x \to e^x$$), there is only a single result within the real numbers but multiple results (and hence defined principle values) within the complex numbers.
 * limited domains: mathematically, some functions are undefined for some values, for example $$\log_e 0$$ is undefined.  or   results are set to the IEEE values of ,   or   in these cases. For example,  gives  . In some cases a function may be undefined for some value when the results are restricted to real numbers, but defined when complex numbers are allowed. For example, there is no $$\sqrt{-1}$$ within the real numbers, but there is within the complex numbers. gives, but  gives . In some cases there is a valid real result but none is returned. For example, $$(-2)^3 = -8$$, but   gives.
 * discontinuities and branch cuts: some functions are discontinuous at some points. A small change in the input can result is an extreme change in the output. For example $$x \to \tan x$$ is discontinuous (and undefined) at $$\pi/2$$. gives   but  gives  . When complex numbers are considered, the discontinuities run along lines (often the axes), and are called branch cuts. The locations of these branch cuts depend on the principle values chosen for the functions, as explained below.
 * negative zeros:  and   also support negative zeros. Most arithmetic functions don't distinguish between   and , but some of the irrational and transcendental functions do. For example  gives   but  gives  . For complex numbers, branch cuts often lie "between"   and  . For example,  gives  and  gives

In many cases these subtleties are not problematic, but at times can conspire to create erroneous calculations. In particular, direct implementation of formulae that are mathematically equivalent may not yield computations that give the same results.

Principle Values and Branch Cuts

The locations of branch cuts depend on the defined principle values.

For example, consider $$z \to e^z$$, as illustrated on the diagram on the right. The red line highlights points $$z$$ on a line on the imaginary axis, extending to infinity in both directions. Per Euler's formula, the mapping of points on the red line by $$z \to e^z$$ all lie on the unit circle, illustrated in blue. The point 0 on the red line maps to 1. As we move up the red line from 0, points map to points anti-clockwise around the circle. $$(\pi/2)i$$ maps to $$i$$ and $$\pi i$$ to $$-1$$. The point $$3i$$ maps to a point just before $$-1$$ and $$4i$$ to a point a little after it. As we move down the red line from 0, points map to points further clockwise from 1. $$-(\pi/2)i$$ maps to $$-i$$ and $$-\pi i$$ maps to $$-1$$. We can see that both $$\pi i$$ and $$-\pi i$$ map to $$-1$$. Similarly $$4i$$ and a point at about $$-2.28i$$ also map to the same place as each other. In fact, the mapping of the red line wraps around the blue circle infinitely many times, so every point on the blue circle has infinitely many points that map to it.

$$x \to e^x$$ maps other vertical lines to other circles centred on the origin. Vertical lines to the left of the red line map to smaller circles, and lines to the right map to larger circles. Points on any one vertical line with imaginary parts at $$\pi$$ and $$-\pi$$ map to the same point as each other, on the negative real axis.

The inverse mathematical function $$z \to \log_e z$$ is the complex logarithm. Sometimes it is useful to consider it multi-valued, as illustrated on the left. Each point $$z$$ (except the origin) will map to points vertically aligned in different layers in the diagram. $$-1$$ maps to $$\pi i$$ and to $$-\pi i$$ (and to infinitely many other points). As $$z$$ travels around a circle, its mappings move around the surface following a helix, and moving up a whole level for each full circuit of the circle. There are no branch cuts.

Sometimes it's more convenient for its range to be restricted so that it has single, principle value. Typically (but not universally), this range is defined as those numbers with imaginary part in the range $$(-\pi, \pi]$$. Then $$-1$$ maps to only the principle value $$\pi i$$. The range of $$z \to \log_e z$$ for all the points on the blue circle is illustrated by the green line (excluding the point $$-\pi i$$), which represents a subset of the points on the original red line. There is a branch cut along the negative real axis: points on it (or just above it) map to points with an imaginary part of (or just less than) $$\pi$$. Points just below it map to points with an imaginary part just greater than $$-\pi$$.

The Haskell function  mirrors the behaviour of $$z \to e^z$$, except for rounding errors. (for  and  ) behaves the same as the restricted, single-valued, function $$z \to log_e z$$, but with a slightly different range due to the presence of negative zeros. It maps points with imaginary part  to points with imaginary part $$\pi$$ and points with imaginary part   to points with imaginary part $$-\pi$$. The branch cut is "between"  and   on the imaginary axis:

The range of  is those numbers with imaginary part in the range $$[-\pi, \pi]$$. It is represented by the green line, including the point $$-\pi i$$.

Both $$-1$$ (under $$z \to log_e z$$) and  (under  ) map to $$\pi i$$, indicated by the filled-in arrow on the diagram. Only  maps (under  ) to $$-\pi i$$, indicated by the unfilled arrow.

One consequence of the branch cut is that  is only the inverse of   for values within the range of  :

There is not a single agreed definition for either the principle values or branch cuts, and they may be different for different types, in other languages, in other systems and in different mathematical usage. It would, for example, be possible for a different (e.g. user-defined) type to define the range of  to be those numbers with imaginary part in the range $$[-\pi/2, 3\pi/2]$$, with a branch cut on the negative imaginary axis.

Rounding and Branch Cuts
Sometimes, rounding errors result in values being the "wrong side" of branch cuts. For example:

is within the range of, so we would expect the result to be. The problem is clear if we look at the intermediate result:

We can see the value has "overshot" $$-1$$ by a little bit, taking it to the wrong side of the branch cut. (Mathematically, $$e^{\pi i} = -1$$. Ideally,  would give , and   would give  ).

In this case, when we use, which operates to greater precision, it behaves as expected:

Unfortunately this problem is sometimes hard to detect and code around. It is also not limited to problems with the inaccuracy of the algorithms for the core functions such as. For example, consider. Mathematically, this should be negative when x > 0, and tend to zero as x increases. To start with, the function behaves as expected:

However, there comes a point when the precision of  means it can't distinguish   and. At this point, the function stops returning a negative value:

This by itself may not be a big problem. But now consider. When x > 0,  should return. However, as soon as x reaches the "failure point", it suddenly jumps to, giving an unexpected discontinuity and an inaccurate result:

A similar problem can occur with branch cuts, e.g. with :

Or with some build-in functions :

Exception Handling
Some numeric operations raise exceptions in some situations, such as division by zero. It would generally be an error to allow these to occur without handling the exceptions. The following sections are some of the ways to deal with this.

An Aside on Avoiding Errors using Types
It is often best to design data types so that it is impossible to write erroneous programs. As a contrived example, compare the following:

with:

The second version would allow  to compile, which would give an error at run-time. The first version ensures we can't write such erroneous code (as well as being a lot easier to read!).

Suppose we tried to adopt this approach to avoid division by zero errors. We could define a  type and redefine   with the type signature. Now we have to fix errors like  at compile time and would never get a division by zero run-time exception.

But at some point we might want to code e.g. . And now we have a problem:
 * we may want to allow either y or z to individually be zero (hence they would not be of type, so we'd need to convert them to   in order to pass the result to  ); and
 * y and z might be the same, so  would be zero and the conversion would fail with a run-time exception that zero is out-of-bounds for.

This attempt to use types to catch division by zero at compile time has failed: we've just swapped one possible run-time exception for another. (And added complexity to the types).

Program logic
One way to avoid run-time exceptions is to include logic in your program, especially at places where you get data from the outside world (e.g. a user).

Here's an example program:

It has a couple of problems, including that the user could type non-integer values (which we'll ignore for now), and that they or they could type in "0".

"Safe" functions
One approach often advocated for pure functions (i.e. where the result depends only on the arguments passed to it) is have the function return  for those values where it "fails". For example, the function:

drops the given prefix from a list, but returns  if the list did not start with it. There are also a number of safe functions in other modules (such as the cunningly named, that provides safe version of list functions such as  ).

Similarly, we could write "safe" versions of  etc:

Although a reasonable approach, it might be quite a challenge to build "safe" versions for all of the functions you use, especially since you would have to check the error conditions for each of them.

Note that you could use  instead of   to similar effect, and this would allow the response to indicate the type of error that occurred (not just that there was one).

Catching Exceptions
Another way to handle exceptions is with. This is defined as:

Both the result of  and its first argument are   monads. The second argument is an "exception handler". When executed,  executes its first argument and, if an exception is raised, the "handler" is executed with the value of the exception passed as an argument. Otherwise, the result is returned as normal.

This works well with many  actions, such as opening a file:

Here's a first attempt at using it in :

Which gives the following:

which isn't quite what we want. The problem is that, as a result of lazy evaluation,  is happy to start displaying the result of   before attempting to evaluate the. The  is only evaluated when   needs the   to evaluate , and this is when the exception is triggered. The behaviour would be the same if the  is outside of the.

However, we can "force" the evaluation of the  earlier, using  :

will create an  action which, when executed, will force evaluation of the , and throw the exception if appropriate.

Note that  doesn't "fully evaluate" expressions. For example, it would not cause an exception in.

Catching Exceptions can be Painful
It might be nice if we could display tables showing how numeric operators worked, like this:

But we need to be careful with operations that throw exceptions, so that we get this:

Our first attempt at  might start like this:

You probably found the conversion to  quite painful. We can no longer construct a string for each line using a pure function, since we want to catch exceptions in the middle of the string. Instead we have to execute  for each cell in the table, handing exceptions as we go, and much more of the code is written in the   monad.

Catching Exceptions in Pure Code
Wouldn't it be nice if we could catch exceptions in pure code? Then we could keep the pure function  in   above, replacing any exceptions with the "-" character we want.

There is a way to do this, using this function with a slightly scary name from the module :

which allows an IO computation to be performed at any time. It comes with a warning: For this to be safe, the IO computation should be free of side effects and independent of its environment. However, we only want to evaluate (pure) expressions and handle the exceptions they throw, so I think we're OK.

We can define:

Now:

Mod3
Let's create a new numeric type that does arithmetic modulo 3, so that addition works like this:

Here's a start:

Note that we can automatically derive instances of many standard classes for this type. Also, this shows that being a "numeric" doesn't necessarily mean we have to use numeric digits (0, 1, 2) to represent the values.

Let's make this an instance of the appropriate numeric classes.

Instance
In order to do addition using, we need to make this an instance of  :

OK - I got bored, so your turn:

Word8T
The standard  type performs arithmetic modulo 256. Sometimes it would be useful to have a type that throws exceptions on overflow instead, so let's create type  that does that.

title: User:Davjam2/Numbers


text:
User talk:119.158.51.228

Hi, I nominated your article for deletion, since it doesn't meet the notability requirements and is not a book. Best, --Jan Myšák (discuss • contribs) 16:00, 17 February 2021 (UTC)

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

title: User talk:119.158.51.228


text:
Understanding Air Safety in the Jet Age/Being a Survivor

Survival factors:

 * Do your research before you book. Airlines going through a financial crunch may skimp on maintenance. Some regulators are a lighter touch than others - if the airline you've chosen is banned from flying in the EU or the US, perhaps you should choose another one.
 * Choose your seat carefully.
 * Listen to the safety instructions and make sure you know where the nearest exits are. All of them as the closest may be unavailable.
 * If something seems wrong, speak up. Several accidents could have been avoided if passengers had told the cabin crew about a problem.
 * Dress appropriately. Artificial fibres are far worse in a fire than natural fibres. The clothes you would have on the ground in an emergency are the clothes on your back, not in your luggage, so wear something generally appropriate for the region you are flying. Unnatural colors help others find you.
 * When emergency oxygen masks fall, always put your own mask on first, then help nearby passengers. If you pass out yourself you aren't helping anyone, but once you have oxygen you can continue to assist others.
 * When asked to stow away items, do so quickly and securely.
 * Have a plan that you've mentally rehearsed. It will help you overcome shock and act quicker.


text:
User:Davjam2/Solutions/Numbers

Numeric Types
1.

These are initial thoughts on appropriate types. The precise requirements may indicate different types are needed.
 * 1) Physical measurements of room and furniture sizes are approximations and probably only accurate to 3 or 4 significant figures.   would be a good choice for an internal representation, storing the dimensions in some particular unit (e.g. metres). You could then round to centimetres, or convert to/from feet and inches, etc, for interaction with the user.
 * 2) Prime numbers are positive integers, and large prime numbers will be outside the limit of numbers that can be represented by an  .   or   would be good choices.
 * 3)   would be a good choice for most currencies (where the main monetary unit is divided into 100 subunits). If the program needs to deal accurately with other currencies (the Maltese Scudo is an extreme, and unlikely, possibility), other types may be required.
 * 4)   or   would be good choices. The fact that they perform modulo arithmetic (and don't give overflow errors) is advantageous here.
 * 5) Either   or , depending on the accuracy required. The hypotenuse of a triangle where the other two sides are both length 1 is $$\sqrt{2}$$, which can't be expressed exactly in any of the standard types. Returning a   would (incorrectly) suggest an accurate rational result. Given the result of the function will be a   or   approximation, the inputs might as well be approximations (to the same precision) too.

2.

3.

4.

5.

Probably not. It can't represent any more than  can (which already offers unlimited size and precision). And it can't represent e.g. $$\tfrac{1}{3}$$ exactly, unlike.

A better idea might be to write (or find) functions to format  numbers as exact decimals when possible or highlight recurring digits when not. (You might like to try this!)

What Numeric Means (The Num Class)
1.

You can check against the actual definition, for example:

being an  might be a bit surprising!

2.

will work with types that only represent integers and will return an integer result. There is also a function  that will return the remainder. (There's also a  that does both together).

will work with types also represent non-integer values, and will return the exact (for e.g. ) or a precise-but-not-exact (for e.g.  ) result of the division, with no concept of "remainder".

3.

Note you can now do any of the following:

Accuracy and Precision
1.

Interestingly, the  function takes an infinite list as a parameter and can return an infinite list as a result. Due to lazy evaluation, this all works fine.

Overflow
1.

y is a positive integer or zero ( is unsigned). Hence adding y to x should give a value greater than or equal to x. If it's less, overflow must have occurred. Is it possibl for overflow to occur yet the result be bigger than x? No: the biggest y can be is 255, and x + 255 is always one less than x (except when x is 0, when no overflow happens).

2.

3.

Here are two different solutions for, each illustrating some (mildly interesting) Haskell. The first uses a single  for two different guards:

The second shows a local function binding:

seems a bit easier with the second version:

Division by Zero
1.

or:

2.

Note that this is equivalent to:

If you're wondering why the y is not needed, read this.

Enumerations
1.

The  functions represent the different combinations of ,   etc. The start value must always be present. The next value and final value are optional, so there are four variations:,  ,   and.

2.

Try for yourself! BUT BE CAREFUL with. You might want to type

Note the rounding errors with  and how the results are consistent with the behaviour of.

3.

You can use it like this:

4.

It won't for the minBound, for example:

5.

You would need to specify the type:

For enumerations with more values than can be represented by an, "wrapping" may occur:

but:

is fine.

Type Classes
1.

Check for yourself!

2.

Note how this now has exactly the same class constraint as the  function that we use, which makes complete sense.

3.

4.

Probably:,  ,  , as well as  ,  ,   and.

5.

Probably:,  ,. Ideally also,   (though we may struggle to implement these).

( has a method   defined as "the rational equivalent of its real argument with full precision" which would be impossible to implement as stated. It would probably be appropriate to return a rational approximation to some stated precision.)

It can't be, since (for example) we can't represent $$\pi$$.

title: User:Davjam2/Solutions/Numbers


text:
Cognitive Science: An Introduction/Brain Development

Sexual Reproduction
Animals that reproduce sexually, like human beings, generate offspring by combining the genetic material from both parents. The mother's DNA is in her eggs, and the male's DNA is encoded in the sperm. When a sperm fertilizes an egg, these genes combine to form the genetic blueprint of the new individual. The vast majority of things we think of as inherited traits of a person are not the result of single genes that code for one protein. Rather, they are the result of many, many genes. Some of these genes come from the mother, some from the father, so the genetic mix an individual gets, and the trait that manifests, is unpredictable in its specifics.

Humans have 23 chromosomes, which contain the 20,000 or so informational genes that describe human beings. DNA encodes how to make proteins and active RNA, when to make them, where to make them, and how much of them to make. See this sidebar for what is meant by informational gene.

What a Protein is: You probably know the term protein in the context of nutrition. In biology, though, proteins are the drivers of the vast majority of subcellular activity. A stretch of physical DNA encodes the base pairs of a protein, which starts as a long string of amino acids, which folds into a complex shape. This shape determines its function. Different mechanisms detect proteins to know when to turn on and off, and how to behave in general. The biological world runs on proteins. See this video: protein folding for a visualization of a protein being created and folding into its final shape.

But not all genetic effects are inherited. An individual egg or sperm might have a mutation or a copying error, which gets passed on the offspring, resulting in a mutation given to the child that neither parent has in their other cells. Each zygote has an average of 70 of these new mutations, but because only about 3% of our genes are used, most of these have no effect. These might contribute to a trait in the child that neither parent has. Down syndrome is a good example of this: a particular egg or sperm gets an extra chromosome, causing the syndrome that neither parent has. It is almost never inherited, but it is genetic.

Development Starts with a Single Cell: The Fertilized Egg
DNA contains instructions for building a body, including brains (for animals that have them.) But the DNA does not encode a full representation of the body that it will help generate. For one thing, DNA does not have enough information to fully describe the location of every cell and every neuron's connections to other neurons. What it has can be thought of as a program that gets carried out by thousands of mindless biochemical machines, and when this happens, a body is formed.

Human beings start off as a single cell that replicates, and then those cells replicate. As they do, the cells start to differentiate. Some cells are neurons in the brain, other cells are skin cells on the foot.

Randomness in Development
But this process is fraught with randomness and noise. The brain has thousands of different neuron types, and not all are created exactly where they are supposed to be. During early development, they move toward where they are supposed to go, crawling like an amoebae. How to these cells know where to go?

As the initial cell divides into two, then four, then eight cells, and so on, the cells start to keep track of three axes in the body: head to tail (called Anterior to Posterior; even humans start out with a tail), back to belly (Dorsal to Ventral), and left to right. Cells release proteins according to where they are on these three axes, and each individual cell "knows" what level of each protein is optimal for its placement in the body. The concentration of this or that protein for this or that axis determine the three-dimensional coordinates in the body, and each cell knows it's supposed to go. When it finds itself in the right place (because the concentration of proteins is correct), then it stops moving.

Once neurons are in the right place, then they need to connect to the correct other neurons. The information receivers of the neurons (the dendrites) and the information senders (the axons) are like arms that grow out of the neuron. Using the same protein gradients that were used to place the cell in its correct location, dendrites and axons snake out into the brain, looking for the right connections. Some of these axons stretch all the way across the brain!

The particular chemical environment surrounding the developing cells in the mother's womb will have subtle effects on early development that have larger effects later on. Small differences in the developmental environment start the brain (and body) in a particular direction, and further development builds on what came before (it it's own environment). As such, two beings with identical DNA will develop into individuals who are not identical.

We can see this with identical twins. They look and act a lot alike, but they are not perfectly similar, even though they were built from the same DNA. We can even see it in our own bodies. The genetic coding for each side of your face is the same, but our faces are not perfectly symmetrical. So when we talk about differences being innate, it refers not only to genetic differences, but developmental differences that have nothing to do with the environment as it is typically conceived (for example, how you were raised by your parents).

The Nature/Nurture Debate
What are you born with, and what is the result of your experiences? Although this question makes intuitive sense, when we look at how development happens, the difference becomes very nuanced. Even if a child has genes that would make them very tall, if raised in an environment with low nutrition, they might still be short. Genes are instructions, and how and when those instructions are carried out depends on the environment.

A good example is puberty. There is no doubt that puberty changes are based on genetic instructions, but these instructions are not used (the genes are not expressed) until a certain point in a child's life, and these triggers are environmental, broadly speaking.

Another example is tanning. When you are out in the sun, it triggers certain genetic codes to express proteins that make you get a tan. When you are out of the sun, the tan fades. Everyone has genes for tanning, but they are on or off depending on environmental conditions.

See the chapter on the Nature-Nurture Debate for more information.


text:
User:Yahaya Lawal Umar

yahaya Lawal Umar

title: User:Yahaya Lawal Umar


text:
User talk:Paveloom

Welcome!
Welcome, Paveloom!

If you have any questions, you can ask in the assistance reading room or possibly contact me personally. —Atcovi (Talk - Contribs) 16:42, 18 February 2021 (UTC)

title: User talk:Paveloom


text:
Talk:SPARQL/Templates

This is cool, but in many or most countries that have a head of government, this person is not called “president.” In many the head of state is.142.161.59.87 (discuss) 23:56, 18 February 2021 (UTC)

title: Talk:SPARQL/Templates


text:
User:MorpheusKafka/US Immigration Law

{| style="width:65%;"
 * style="background-color: cream; border: solid 1px gray; padding: 1em;" valign="top" |

Chapters

 * /Mens rea/
 * /Actus reus/
 * /Summary/

 * /Preliminary offenses/
 * /Search and seizure/
 * /Defenses/

 * }

title: User:MorpheusKafka/US Immigration Law


text:
Wikibooks:Reading room/Proposals/2020/October

Proposal: add features that support ebook writers better
Hi there, on the general discussion yesterday I mentioned that I would find it useful to have many of the features of Wikisource available here. This would allow creation of books that feel like books, and export well to epub / mobi formats. Specifically we could support: Wikisource has developed all of this to support replicating books. Most ebooks have copied this formula more or less as they are produced with print editions. Wikibooks could offer these features as a option for book developers who believe their audience is primarily offline rather than online.
 * optional narrow single column formats;
 * optional serif fonts for body text
 * Differing styles for headings and so on (not always underlines)
 * easy navigation bars (last page, next page)
 * optional export links to common ebook formats

I suspect the work involved is not too great, as the code should already exist. But I can't say for sure, some things like layout options might break some pages and need to be enabled case by case therefore. Similarly many Wikibooks won't export well to epub due to the way tables are not properly supported by many readers.

I think this could open Wikibooks usage to a lot more use cases. I am certainly missing being able to do things along these lines for some book ideas I have, like sample language readers and dual language readers for learners. These don't suit Wikisource as they're incomplete extracts, potentially with editing or simplification, but don't work too well here because the destination format is not currently well supported. JimKillock (discuss • contribs) 07:57, 22 April 2020 (UTC)
 * Jim, has a lot more templates for formatting text. Have you poked around there to see what our sister project has for formatting in a MediaWiki context? —Justin ( koavf ) ❤T☮C☺M☯ 08:25, 22 April 2020 (UTC)
 * Yes absolutely, I have been doing a chunk of work there and that is what prompted me to make these suggestions. Is it just a question of me going ahead and copying templates over? or should I suggest which might be brought over and why? (That said I've not investigated the way the page formatting templates work, perhaps these are also imply traditional templates.) JimKillock (discuss • contribs) 17:14, 22 April 2020 (UTC)
 * I am active in Persian Wikibooks and there these two issues are on rise, too: Author rights and issuing books. I believe that writers and editors in Wikibooks differ with writers and editors of Wikipedia. In Wikibooks authors are eager to register their names (or usernames as nicknames) on a separate page inside the book, e.g. Wikijunior:The Elements/Authors and Wikijunior:Ancient Civilizations/Authors. Considering practices for issuing knowledge, Wikibooks is different from Wikipedia, too. Print version is a feature more important for Wikibooks than Wikipedia as the content of Wikibooks is supposed to be used by learners (better called readers) who may prefer an offline version of the book. In my opinion, PDF version is good enough as it can be converted to epub just by one click using softwares even available online. --Doostdar (discuss • contribs) 18:11, 22 April 2020 (UTC)
 * I don't personally agree that pdf » epub conversion is a great idea (epub is basically html so Wiki to epub is natural where PDF’s basis in postscript does not convert so well back to html); but luckily we don't have to choose; Wikimedia already has the tools. The question then is how to make exports easy for readers who are more likely to want that as you say.
 * I really like the way Italian Wikisource have enabled exports for instance, see this example I was recently shown. JimKillock (discuss • contribs) 19:16, 22 April 2020 (UTC)
 * We certainly can copy templates: they are all freely licensed. It's usually better to have someone with the appropriate user rights to do this via Special:Import. I brought up Wikisource only because you may be able to identify existing solutions to some of these problems you raise. —Justin ( koavf ) ❤T☮C☺M☯ 19:37, 22 April 2020 (UTC)
 * Thank you Justin, that is very helpful. JimKillock (discuss • contribs) 21:42, 22 April 2020 (UTC)
 * There are some differences between the provisions for css on different projects, which probably should be kept in mind when contemplating introducing advanced formatting from another project. This may both complicate things and allow some interesting new techniques.  (Alas, I have some awareness of the Wikibooks infrastructure, and more about the Wikinews infrastructure, but no past experience with the Wikisource infrastructure.)
 * Different projects may have very different approaches to their customized css. Wikisource appears to have a very small, simple common.css; either there must be some additional css, perhaps induced somewhere by javascript, or perhaps it's all done using javascript instead of css.  Wikibooks does a lot more in its common.css, a lot of it arranged modularly in subpages.  (For contrast, the Wikinews common.css is all on the one page, which makes it considerably harder to read.)
 * Wikibooks has book-specific css pages: our common.js checks for the existence of a subpage for the book, and imports it if found. (Then again, Wikinews has page-specific css pages, also checked for and imported by its common.js.)
 * The javascript infrastructures are also different between projects. Wikibooks common.js provides for both book-specific and page-specific javascript pages, and its common.js is largely modular.  The page-specific javascript, btw, is key to the dialog tools, and was adapted from Wikinews — changing the naming-convention for the page-specific javascript pages, because the Wikinews convention conflicted with the modularity naming-convention of Wikibooks.  (Yes, the Wikinews common.js is all on one page, yes that makes it very hard to read, and yes I have considered modularizing it.)
 * --Pi zero (discuss • contribs) 01:31, 23 April 2020 (UTC)

Interesting post Pi zero, but some comments on it:
 * I believe that the bulk of the Wikisource site-css is at MediaWiki:Gadget-Site.css. For some reason some mediawiki wikis use this file rather than the common.css used by others; see mw:Manual:CSS.
 * Custom CSS is now rather easy due to TemplateStyles: see mw:Extension:TemplateStyles. The chief advantage over perbook css is that you don't need admin access to edit, making it easier for most users; also it can be added to any page without the need for it to correspond to a particular book. Despite the name, TemplateStyles can be applied to non-template namespaces, and I have created Template:TemplateStyles/Oberon/styles.css to do so.
 * But if custom JS is needed it still needs to be done through perbook JS. -- Jules (Mrjulesd) 12:48, 23 April 2020 (UTC)
 * I'm interested to hear where the css might be hiding in the Wikisource infrastructure. (Yes, I'm familiar with this sort of use of gadgets.) --Pi zero (discuss • contribs) 18:03, 23 April 2020 (UTC)
 * Well it does actually hide in MediaWiki:Gadget-Site.css; despite its name it actually contains the bulk of the site-wide CSS. A similar situation is with the www.mediawiki.org site; if you look at mw:MediaWiki:Common.css its empty, and its site-wide CSS is actually held at mw:MediaWiki:Gadget-site.css. The reason given for this is that "MediaWiki.org controls site CSS with the Gadgets extension, so MediaWiki:Gadget-site.css is used in place of MediaWiki:Common.css. This results in a slightly different load URL." -- Jules (Mrjulesd) 18:29, 23 April 2020 (UTC)
 * What is the right thing for me to do to move this forward? Should I make a list of templates I would like to have moved over? JimKillock (discuss • contribs) 10:17, 25 April 2020 (UTC)
 * That could help to make it all more concrete; we've probably taken the purely abstract discussion of project infrastructures about as far as it can go. --Pi zero (discuss • contribs) 12:09, 25 April 2020 (UTC)
 * OK, so here we go, these would be the things I would suggest as a start:
 * s:Template:Default_layout » allows differing page layouts to be displayed by default;
 * s:Help:Layout » explains the layout system, which I don't understand behind the scenes however
 * s:Template:Larger » allows non-underlined headings of varying sizes
 * s:Template:Smaller » allows text of smaller sizes than body text
 * s:Template:Header » creates title display area with key info, plus navigation back / forward
 * s:la:Formula:Titulus » Creates a title area for a front page, also used by ebook exports for front page material AFAICT;
 * s:la:Formula:WSExport » Presents a series of export formats for a given book
 * Yikes. That does look rather... involved.  It appears, at first blush, also to have some assumptions built into it about uniformity across the project, that are true for Wikisource but wouldn't be for all of Wikibooks.  I hope I'll have a chance to take a closer look sometime in the nearish future... --Pi zero (discuss • contribs) 16:05, 25 April 2020 (UTC)
 * Thanks, I guess it is the layout system that looks complex. If there is a simpler way of achieving the goal of a narrow column plus serif fonts, maybe we could consider that?
 * The other templates ought to be quite simple (I could be wrong).
 * Thought I would flag that it'd be good to think of a simpler way to get the desired result – I don't want to make this stall! If I can help in any way, please let me know. I can bodge around CSS a bit. JimKillock (discuss • contribs) 08:08, 29 April 2020 (UTC)
 * See the list above, but especially s:la:Formula:Titulus; now in active use, eg Ólim JimKillock (discuss • contribs) 22:13, 3 May 2020 (UTC)

Hi ; I thought I would ask as it has been a month since we last spoke whether you'd been able to think about the practicalities of doing this a bit more? JimKillock (discuss • contribs) 07:49, 3 June 2020 (UTC)
 * Hey, did you have time to think about this a bit more? I have a bunch of projects I feel would only work with something along these lines which I am holding off while we decide what to do.
 * If the answer is that it is too difficult given how Wikibooks is set up, then I think we need to know, perhaps for instance to consider a clone of Wikisource for ebook production. EWikibooks? JimKillock (discuss • contribs) 11:40, 2 July 2020 (UTC)
 * Very much hoping someone can help / respond. I have a couple of projects where I want to combine English and Latin for e-book export. These fall outside of the Wikisource criteria - they would either reprocess / correct / add accentation, add new translations, link to musical content, etc.
 * If I can't do this on Wikibooks, then I cannot see how to develop these projects on a Wikimedia platform. Yet surely this is exactly what Wikibooks is for. So I am at a loss and now a little disappointed that we are unable to come a clear answer - even a firm "no" after three months. JimKillock (discuss • contribs) 12:16, 9 August 2020 (UTC)
 * /me hopes to take a close look at this tomorrow. --Pi zero (discuss • contribs) 00:34, 10 August 2020 (UTC)
 * quick mention in case you have time to take another look! JimKillock (discuss • contribs) 06:55, 22 October 2020 (UTC)


text:
User:Margtom

Refurinn og landnámsmenn

Einu sinni bjuggu engar manneskjur á Íslandi. Í kringum árið 870 fór að koma hingað fólk siglandi á bátum sem námu land. Yfirleitt er talað um menn sem voru landnámsmenn en þó eru líka þekktar nokkrar konur sem voru landnámsmenn. Hefur þú heyrt talað um Hrafna - Flóka, Ingólf Arnarson eða um Auði djúpúðgu en þau voru öll landnámsmenn. Þegar þau komu til Íslands var refurinn eina landspendýrið sem þau fundu. Líklega hefur hann komið hingað með hafís frá Grænlandi.

Refur er af hundaætt. Hann er skyldur hundum og úlfum. Hann er því frekar líkur hundum að útliti en miklu minni. Refurinn er 3–4 kg og 90 cm langur frá trýni og aftur á skottbrodd. En skottið sjálft er 30 cm langt og mjög þykkt. Þegar refurinn sefur hringar hann skottið yfir leggi sína og trýni til að hlýja sér.

Refurinn er á ferðinni 12–14 klukkutíma á sólarhring, einkum í ljósaskiptunum (þegar byrjað er að rökkva).

Refurinn étur smádýr og fugla en þó kemur fyrir að refur drepi lömb. Slíkur refur er kallaður dýrbítur. Nú á dögum eru dýrbítir sjaldgæfir. Grenjaskyttur kallast þeir sem veiða refi á sumrin til að koma í veg fyrir að þeir drepi lömb. Veiðarnar eru kallaðar grenjavinnsla. Refir eru líka veiddir á veturna.

Íslenski refurinn hefur mörg nöfn. Hann er stundum kallaður: melrakki, tófa, lágfóta og skolli.

title: User:Margtom


text:
User talk:Sarina Beier

Welcome
Welcome to Wikibooks, Sarina Beier!

 First steps tutorial Wikibooks is for collaborative development of free textbooks.

You do not need technical skills to contribute. You can easily change most books. Please introduce yourself, and let us know what interests you.

If you already contribute at other Wikimedia projects, our Wikimedia Orientation should quickly get you started. (Would you like to provide feedback on this message?)

  Getting help   Made a mistake?   Goodies, tips and tricks
 * Read the Using Wikibooks book for a friendly introduction to the project, or our help pages for more information.
 * You can get friendly help from the community in the user assistance room or our IRC channel.
 * Upload freely licensed files to Wikimedia Commons. You may request permission to upload fair use files locally. Please include author and source information and a non-free use rationale for non-free files.
 * You can restore a previously saved version.
 * Pages should follow the  naming convention.
 * Need to rename a page? Use the move tab (is available once your account is 4 days old - until then, ask for help).
 * To request a page be deleted, add to the top of the page.
 * Was a page you made deleted? Please read the deletion policy, and check the deletion log to find out why. Also check the RFD archives if applicable. You can request undeletion at WB:RFU, or ask the administrator who deleted the page.
 * Please fill in the edit summary and preview your edits before saving.
 * Sign your name on discussion pages by typing ~~~~
 * User scripts can make many tasks easier. Look at the Gadgets tab of my preferences; check off the boxes for the scripts you want, and hit save!

-- Jules (Mrjulesd) 11:53, 19 February 2021 (UTC)

title: User talk:Sarina Beier


text:
Oberon/V2/OCE

MODULE OCE; (*NW 7.6.87 / 5.3.91*) IMPORT SYSTEM, OCS, OCT, OCC; CONST (*instruction format prefixes*) F6 = 4EH; F7 = 0CEH; F9 = 3EH; F11 = 0BEH; (*frequent operation codes: 5C, 5D, 5F = MOVQi, 14, 15, 17 = MOVi, 27 = ADDR*) (*object and item modes*) Var = 1; VarX = 2; Ind = 3; IndX = 4; RegI = 5; RegX = 6; Abs = 7; Con = 8; Stk = 9; Coc = 10; Reg = 11; Fld = 12; Typ = 13; (*structure forms*) Undef = 0; Byte = 1; Bool = 2; Char = 3; SInt = 4; Int = 5; LInt = 6; Real = 7; LReal = 8; Set = 9; String = 10; NilTyp = 11; NoTyp = 12; Pointer = 13; ProcTyp = 14; Array = 15; DynArr = 16; Record = 17; VAR inxchk*: BOOLEAN; log: INTEGER; (*side effect of mant*) lengcode: ARRAY 18 OF INTEGER; intSet, realSet: SET; PROCEDURE inverted(x: LONGINT): LONGINT; BEGIN (*inverted sense of condition code*) IF ODD(x) THEN RETURN x-1 ELSE RETURN x+1 END END inverted; PROCEDURE load(VAR x: OCT.Item); VAR y: OCT.Item; BEGIN IF x.mode < Reg THEN y := x; OCC.GetReg(x); IF (y.mode = Con) & (-8 <= y.a0) & (y.a0 <= 7) THEN OCC.PutF2(lengcode[x.typ.form] + 5CH, y.a0, x) 			ELSE OCC.PutF4(lengcode[x.typ.form] + 14H, x, y) 			END ELSIF x.mode > Reg THEN OCS.Mark(126) END END load; PROCEDURE loadX(VAR x: OCT.Item); VAR y: OCT.Item; BEGIN IF x.mode <= Reg THEN y := x; OCC.GetReg(x); IF (y.mode = Con) & (-8 <= y.a0) & (y.a0 <= 7) THEN OCC.PutF2(5FH, y.a0, x) 			ELSE OCC.Put(F7, lengcode[x.typ.form] + 1CH, x, y) (*MOVXiD*) END ELSIF x.mode > Reg THEN OCS.Mark(126) END END loadX; PROCEDURE loadF(VAR x: OCT.Item); VAR y: OCT.Item; BEGIN IF x.mode < Reg THEN y := x; OCC.GetFReg(x); OCC.Put(F11, lengcode[x.typ.form] + 4, x, y) (*MOVf*) ELSIF x.mode > Reg THEN OCS.Mark(126) END END loadF; PROCEDURE loadB(VAR x: OCT.Item); (*Coc-Mode*) VAR L0, L1: LONGINT; BEGIN IF (x.a1 = 0) & (x.a2 = 0) THEN L0 := x.a0; OCC.GetReg(x); OCC.PutF2(3CH, L0, x) 		ELSE OCC.PutF0(inverted(x.a0)); OCC.PutWord(x.a2); L0 := OCC.pc - 2; OCC.FixLink(x.a1); OCC.GetReg(x); OCC.PutF2(5CH, 1, x); OCC.PutF0(14); L1 := OCC.pc; OCC.PutWord(0); OCC.FixLink(L0); OCC.PutF2(5CH, 0, x); OCC.fixup(L1) END END loadB; PROCEDURE loadAdr(VAR x: OCT.Item); VAR y: OCT.Item; BEGIN IF x.mode < Con THEN y := x; OCC.GetReg(x); IF (y.mode = Ind) & (y.a1 = 0) THEN y.mode := Var; OCC.PutF4(17H, x, y) 			ELSE OCC.PutF4(27H, x, y); x.a1 := 0 END ; x.mode := RegI; x.obj := NIL ELSE OCS.Mark(127) END END loadAdr; PROCEDURE setCC(VAR x: OCT.Item; cc: LONGINT); BEGIN x.typ := OCT.booltyp; x.mode := Coc; x.a0 := cc; x.a1 := 0; x.a2 := 0 END setCC; PROCEDURE cmp(L: INTEGER; VAR x, y: OCT.Item); BEGIN IF (y.mode = Con) & (y.a0 <= 7) & (y.a0 >= -8) THEN OCC.PutF2(L+1CH, y.a0, x) (*CMPQi*) ELSE OCC.PutF4(L+4, x, y) (*CMPi*) END END cmp; PROCEDURE add(L: INTEGER; VAR x, y: OCT.Item); BEGIN IF (y.mode = Con) & (y.a0 <= 7) & (y.a0 >= -8) THEN OCC.PutF2(L+0CH, y.a0, x) (*ADDQi*) ELSE OCC.PutF4(L, x, y) (*ADDi*) END END add; PROCEDURE sub(L: INTEGER; VAR x, y: OCT.Item); BEGIN IF (y.mode = Con) & (y.a0 <= 8) & (y.a0 >= -7) THEN OCC.PutF2(L+0CH, -y.a0, x) (*ADDQi*) ELSE OCC.PutF4(L+20H, x, y) (*SUBi*) END END sub; PROCEDURE mant(x: LONGINT): LONGINT; (*x DIV 2^log*) BEGIN log := 0; IF x > 0 THEN WHILE ~ODD(x) DO x := x DIV 2; INC(log) END END ; RETURN x 	END mant; PROCEDURE SetIntType*(VAR x: OCT.Item); VAR v: LONGINT; BEGIN v := x.a0; IF (-80H <= v) & (v <= 7FH) THEN x.typ := OCT.sinttyp ELSIF (-8000H <= v) & (v <= 7FFFH) THEN x.typ := OCT.inttyp ELSE x.typ := OCT.linttyp END END SetIntType; PROCEDURE AssReal*(VAR x: OCT.Item; y: REAL); BEGIN SYSTEM.PUT(SYSTEM.ADR(x.a0), y) 	END AssReal; PROCEDURE AssLReal*(VAR x: OCT.Item; y: LONGREAL); BEGIN SYSTEM.PUT(SYSTEM.ADR(x.a0), y) 	END AssLReal; PROCEDURE Index*(VAR x, y: OCT.Item); VAR f, n: INTEGER; i: LONGINT; eltyp: OCT.Struct; y1, z: OCT.Item; BEGIN f := y.typ.form; IF ~(f IN intSet) THEN OCS.Mark(80); y.typ := OCT.inttyp END ; IF x.typ = NIL THEN HALT(80) END ; IF x.typ.form = Array THEN eltyp := x.typ.BaseTyp; n := x.typ.n; 			IF eltyp = NIL THEN HALT(81) END ; IF y.mode = Con THEN IF (0 <= y.a0) & (y.a0 < n) THEN i := y.a0 * eltyp.size ELSE OCS.Mark(81); i := 0 END ; IF x.mode = Var THEN INC(x.a0, i) 				ELSIF (x.mode = Ind) OR (x.mode = RegI) THEN INC(x.a1, i); x.obj := NIL ELSE loadAdr(x); x.a1 := i 				END ELSE IF inxchk THEN (*z = bound descr*) z.mode := Var; z.a0 := x.typ.adr; z.lev := -x.typ.mno; IF y.mode = Reg THEN y1 := y ELSE OCC.GetReg(y1) END ; IF f = SInt THEN OCC.Put(F7, 10H, y1, y); y := y1 END ; (*MOVXBW*) OCC.Put(0EEH, SHORT(y1.a0)*8+1, y, z); OCC.PutF1(0D2H) (*CHECK, FLAG*) ELSE IF f = LInt THEN load(y) ELSE loadX(y) END ; y1 := y 				END ; f := x.mode; IF x.mode = Var THEN x.mode := VarX; x.a2 := y1.a0 				ELSIF x.mode = Ind THEN x.mode := IndX; x.a2 := y1.a0 				ELSIF x.mode = RegI THEN x.mode := RegX; x.a2 := y1.a0 				ELSIF x.mode IN {VarX, IndX, RegX} THEN z.mode := Con; z.typ := OCT.inttyp; z.a0 := (x.typ.size DIV eltyp.size) - 1; OCC.Put(2EH, SHORT(x.a2)*8+5, y1, z) (*INDEX*) ELSE loadAdr(x); x.mode := RegX; x.a1 := 0; x.a2 := y1.a0 				END END ; x.typ := eltyp ELSIF x.typ.form = DynArr THEN IF inxchk THEN z.mode := Var; z.a0 := x.a0 + x.typ.adr; z.lev := x.lev; IF y.mode = Reg THEN y1 := y ELSE OCC.GetReg(y1) END ; IF f = SInt THEN IF y.mode = Con THEN y.typ := OCT.inttyp ELSE OCC.Put(F7, 10H, y1, y); y := y1 					END END ; OCC.Put(0EEH, SHORT(y1.a0)*8+1, y, z); OCC.PutF1(0D2H) (*CHECK, FLAG*) ELSE IF f = LInt THEN load(y) ELSE loadX(y) END ; y1 := y 			END ; IF x.mode IN {Var, Ind} THEN x.mode := IndX; x.a2 := y1.a0 			ELSIF x.mode = RegI THEN x.mode := RegX; x.a2 := y1.a0 			ELSIF x.mode IN {IndX, RegX} THEN z.mode := Var; z.a0 := x.a0 + x.typ.adr; z.lev := x.lev; OCC.Put(2EH, SHORT(x.a2)*8+5, y1, z) (*INDEX*) ELSE loadAdr(x); x.mode := RegX; x.a1 := 0; x.a2 := y1.a0 			END ; x.typ := x.typ.BaseTyp ELSE OCS.Mark(82) END END Index; PROCEDURE Field*(VAR x: OCT.Item; y: OCT.Object); BEGIN (*x.typ.form = Record*) IF (y # NIL) & (y.mode = Fld) THEN IF x.mode = Var THEN INC(x.a0, y.a0) ELSIF (x.mode = Ind) OR (x.mode = RegI) THEN INC(x.a1, y.a0) ELSE loadAdr(x); x.mode := RegI; x.a1 := y.a0 			END ; x.typ := y.typ; x.obj := NIL ELSE OCS.Mark(83); x.typ := OCT.undftyp; x.mode := Var END END Field; PROCEDURE DeRef*(VAR x: OCT.Item); BEGIN IF x.typ.form = Pointer THEN IF (x.mode = Var) & (x.lev >= 0) THEN x.mode := Ind ELSE load(x); x.mode := RegI END ; x.typ := x.typ.BaseTyp; x.obj := OCC.wasderef ELSE OCS.Mark(84) END ; x.a1 := 0 END DeRef; PROCEDURE TypTest*(VAR x, y: OCT.Item; test: BOOLEAN); PROCEDURE GTT(t0, t1: OCT.Struct; varpar: BOOLEAN); VAR t: OCT.Struct; xt, tdes, p: OCT.Item; BEGIN IF t0 # t1 THEN t := t1; REPEAT t := t.BaseTyp UNTIL (t = NIL) OR (t = t0); IF t # NIL THEN x.typ := y.typ; IF OCC.typchk OR test THEN xt := x; 						IF varpar THEN xt.mode := Ind; xt.a0 := x.a0+4 ELSIF (x.mode = Var) & (x.lev >= 0) THEN xt.mode := Ind; xt.a1 := -4; load(xt); xt.mode := RegI ELSE load(xt); p := xt; p.mode := RegI; p.a1 := -4; OCC.PutF4(17H, xt, p); (*MOVD -4(xt), xt *) xt.mode := RegI END ; xt.a1 := t1.n * 4; tdes.mode := Var; tdes.lev := -t1.mno; tdes.a0 := t1.adr; OCC.PutF4(7, tdes, xt); (*CMPD*) IF ~test THEN OCC.PutF0(0); OCC.PutDisp(4); OCC.PutF1(0F2H); OCC.PutByte(18) ELSE setCC(x, 0) END END ELSE OCS.Mark(85); IF test THEN x.typ := OCT.booltyp END END ELSIF test THEN setCC(x, 14) END END GTT; BEGIN IF x.typ.form = Pointer THEN IF y.typ.form = Pointer THEN GTT(x.typ.BaseTyp, y.typ.BaseTyp, FALSE) ELSE OCS.Mark(86) END ELSIF (x.typ.form = Record) & (x.mode = Ind) & (x.obj # NIL) & (x.obj # OCC.wasderef) & (y.typ.form = Record) THEN GTT(x.typ, y.typ, TRUE) ELSE OCS.Mark(87) END END TypTest; PROCEDURE In*(VAR x, y: OCT.Item); VAR f: INTEGER; BEGIN f := x.typ.form; IF (f IN intSet) & (y.typ.form = Set) THEN IF y.mode = Con THEN load(y) END ; OCC.PutF4(lengcode[f]+34H, y, x); setCC(x, 8) (*TBITi*) ELSE OCS.Mark(92); x.mode := Reg END ; x.typ := OCT.booltyp END In; PROCEDURE Set0*(VAR x, y: OCT.Item); VAR one: LONGINT; BEGIN x.mode := Reg; x.a0 := 0; x.typ := OCT.settyp; IF y.typ.form IN intSet THEN IF y.mode = Con THEN x.mode := Con; IF (0 <= y.a0) & (y.a0 < 32) THEN one := 1; x.a0 := SYSTEM.LSH(one, y.a0) ELSE OCS.Mark(202) END ELSE OCC.GetReg(x); OCC.PutF2(5FH, 1, x); OCC.Put(F6, 17H, x, y) (*LSHD*) END ELSE OCS.Mark(93) END END Set0; PROCEDURE Set1*(VAR x, y, z: OCT.Item); VAR s: LONGINT; BEGIN x.mode := Reg; x.a0 := 0; x.typ := OCT.settyp; IF (y.typ.form IN intSet) & (z.typ.form IN intSet) THEN IF y.mode = Con THEN IF (0 <= y.a0) & (y.a0 < 32) THEN y.typ := OCT.settyp; s := -1; y.a0 := SYSTEM.LSH(s, y.a0); IF z.mode = Con THEN x.mode := Con; IF (y.a0 <= z.a0) & (z.a0 < 32) THEN s := -2; x.a0 := y.a0-SYSTEM.LSH(s, z.a0) ELSE OCS.Mark(202); x.a0 := 0 END ELSIF y.a0 = -1 THEN OCC.GetReg(x); OCC.PutF2(5FH, -2, x); OCC.Put(F6, 17H, x, z); OCC.Put(F6, 37H, x, x) (*LSHD, COMD*) ELSE OCC.GetReg(x); OCC.PutF4(17H, x, y); OCC.GetReg(y); OCC.PutF2(5FH, -2, y); OCC.Put(F6, 17H, y, z); OCC.PutF4(0BH, x, y) 					END ELSE OCS.Mark(202) END ELSE OCC.GetReg(x); OCC.PutF2(5FH, -1, x); OCC.Put(F6, 17H, x, y); IF z.mode = Con THEN IF (0 <= z.a0) & (z.a0 < 32) THEN y.typ := OCT.settyp; y.mode := Con; s := -2; y.a0 := SYSTEM.LSH(s, z.a0) ELSE OCS.Mark(202) END ELSE OCC.GetReg(y); OCC.PutF2(5FH, -2, y); OCC.Put(F6, 17H, y, z) (*LSHD*) END ; OCC.PutF4(0BH, x, y) (*BICD*) END ELSE OCS.Mark(93) END END Set1; PROCEDURE MOp*(op: INTEGER; VAR x: OCT.Item); VAR f, L: INTEGER; a: LONGINT; y: OCT.Item; BEGIN f := x.typ.form; CASE op OF 				5: (*&*) IF x.mode = Coc THEN OCC.PutF0(inverted(x.a0)); OCC.PutWord(x.a2); x.a2 := OCC.pc-2; OCC.FixLink(x.a1) ELSIF (x.typ.form = Bool) & (x.mode # Con) THEN OCC.PutF2(1CH, 1, x); setCC(x, 0); OCC.PutF0(1); OCC.PutWord(x.a2); x.a2 := OCC.pc-2; OCC.FixLink(x.a1) ELSIF x.typ.form # Bool THEN OCS.Mark(94); x.mode := Con; x.typ := OCT.booltyp; x.a0 := 0 END | 6: (*+*) 				IF ~(f IN intSet + realSet) THEN OCS.Mark(96) END | 7: (*-*) 				y := x; L := lengcode[f]; IF f IN intSet THEN IF x.mode = Con THEN x.a0 := -x.a0; SetIntType(x) ELSE OCC.GetReg(x); OCC.Put(F6, L+20H, x, y) (*NEGi*) END ELSIF f IN realSet THEN OCC.GetFReg(x); OCC.Put(F11, L+14H, x, y) (*NEGf*) ELSIF f = Set THEN OCC.GetReg(x); OCC.Put(F6, 37H, x, y) (*COMD*) ELSE OCS.Mark(97) END | 8: (*OR*) IF x.mode = Coc THEN OCC.PutF0(x.a0); OCC.PutWord(x.a1); x.a1 := OCC.pc-2; OCC.FixLink(x.a2) ELSIF (x.typ.form = Bool) & (x.mode # Con) THEN OCC.PutF2(1CH, 1, x); setCC(x, 0); OCC.PutF0(0); OCC.PutWord(x.a1); x.a1 := OCC.pc-2; OCC.FixLink(x.a2) ELSIF x.typ.form # Bool THEN OCS.Mark(95); x.mode := Con; x.typ := OCT.booltyp; x.a0 := 1 END | 9 .. 14: (*relations*) IF x.mode = Coc THEN loadB(x) END | 32: (*~*) 				IF x.typ.form = Bool THEN IF x.mode = Coc THEN x.a0 := inverted(x.a0); a := x.a1; x.a1 := x.a2; x.a2 := a 					ELSE OCC.PutF2(1CH, 0, x); setCC(x, 0) END ELSE OCS.Mark(98) END END END MOp; PROCEDURE convert1(VAR x: OCT.Item; typ: OCT.Struct); VAR y: OCT.Item; op: INTEGER; BEGIN IF x.mode # Con THEN y := x; 			IF typ.form = Int THEN op := 10H ELSE op := lengcode[x.typ.form] + 1CH END; IF x.mode < Reg THEN OCC.GetReg(x) END ; OCC.Put(F7, op, x, y) (*MOVij*) END ; x.typ := typ END convert1; PROCEDURE convert2(VAR x: OCT.Item; typ: OCT.Struct); VAR y: OCT.Item; BEGIN y := x; OCC.GetFReg(x); (*MOVif*) OCC.Put(F9, lengcode[typ.form]*4 + lengcode[x.typ.form], x, y); x.typ := typ END convert2; PROCEDURE convert3(VAR x: OCT.Item); VAR y: OCT.Item; BEGIN y := x; 		IF x.mode < Reg THEN OCC.GetFReg(x) END ; OCC.Put(F9, 1BH, x, y); x.typ := OCT.lrltyp (*MOVFL*) END convert3; PROCEDURE Op*(op: INTEGER; VAR x, y: OCT.Item); VAR f, g, L: INTEGER; p, q, r: OCT.Struct; PROCEDURE strings: BOOLEAN; BEGIN RETURN ((((f=Array) OR (f=DynArr)) & (x.typ.BaseTyp.form=Char)) OR (f=String)) & ((((g=Array) OR (g=DynArr)) & (y.typ.BaseTyp.form=Char)) OR (g=String)) END strings PROCEDURE CompStrings(cc: INTEGER; Q: BOOLEAN); VAR z: OCT.Item; BEGIN z.mode := Reg; z.a0 := 2; IF f = DynArr THEN OCC.DynArrAdr(z, x) 			ELSE OCC.PutF4(27H, z, x) 			END ; z.a0 := 1; IF g = DynArr THEN OCC.DynArrAdr(z, y) 			ELSE OCC.PutF4(27H, z, y) 			END ; z.a0 := 0; OCC.PutF2(5FH, -1, z); (*MOVQD -1, R0*) z.a0 := 4; OCC.PutF2(5FH, 0, z); (*MOVQD 0, R4*) OCC.PutF1(14); OCC.PutF1(4); OCC.PutF1(6); (*CMPSB 6*) IF Q THEN (*compare also with zero byte*) OCC.PutF0(9); OCC.PutDisp(5); (*BFC*) z.mode := RegI; z.a0 := 2; z.a1 := 0; OCC.PutF2(1CH, 0, z) (*CMPQB*) END ; setCC(x, cc) END CompStrings PROCEDURE CompBool(cc: INTEGER); BEGIN IF y.mode = Coc THEN loadB(y) END ; OCC.PutF4(4, x, y); setCC(x, cc) END CompBool; BEGIN IF x.typ # y.typ THEN g := y.typ.form; CASE x.typ.form OF 					Undef: | SInt: IF g = Int THEN convert1(x, y.typ) ELSIF g = LInt THEN convert1(x, y.typ) ELSIF g = Real THEN convert2(x, y.typ) ELSIF g = LReal THEN convert2(x, y.typ) ELSE OCS.Mark(100) END | Int: IF g = SInt THEN convert1(y, x.typ) ELSIF g = LInt THEN convert1(x, y.typ) ELSIF g = Real THEN convert2(x, y.typ) ELSIF g = LReal THEN convert2(x, y.typ) ELSE OCS.Mark(100) END | LInt: IF g = SInt THEN convert1(y, x.typ) ELSIF g = Int THEN convert1(y, x.typ) ELSIF g = Real THEN convert2(x, y.typ) ELSIF g = LReal THEN convert2(x, y.typ) ELSE OCS.Mark(100) END | Real: IF g = SInt THEN convert2(y, x.typ) ELSIF g = Int THEN convert2(y, x.typ) ELSIF g = LInt THEN convert2(y, x.typ) ELSIF g = LReal THEN convert3(x) ELSE OCS.Mark(100) END | LReal: IF g = SInt THEN convert2(y, x.typ) ELSIF g = Int THEN convert2(y, x.typ) ELSIF g = LInt THEN convert2(y, x.typ) ELSIF g = Real THEN convert3(y) ELSE OCS.Mark(100) END | NilTyp:   IF g # Pointer THEN OCS.Mark(100) END | Pointer: IF g = Pointer THEN p := x.typ.BaseTyp; q := y.typ.BaseTyp; IF (p.form = Record) & (q.form = Record) THEN IF p.n < q.n THEN r := p; p := q; q := r END; WHILE (p # q) & (p # NIL) DO p := p.BaseTyp END; IF p = NIL THEN OCS.Mark(100) END ELSE OCS.Mark(100) END ELSIF g # NilTyp THEN OCS.Mark(100) END | ProcTyp: IF g # NilTyp THEN OCS.Mark(100) END | Array, DynArr, String: | Byte, Bool, Char, Set, NoTyp, Record: OCS.Mark(100) END END ; f := x.typ.form; g := y.typ.form; L := lengcode[f]; CASE op OF 				1: IF f IN intSet THEN (***) IF (x.mode = Con) & (y.mode = Con) THEN (*ovfl test missing*) x.a0 := x.a0 * y.a0; SetIntType(x) ELSIF (x.mode = Con) & (mant(x.a0) = 1) THEN x.a0 := log; x.typ := OCT.sinttyp; load(y); OCC.Put(F6, L+4, y, x); (*ASHi*) x := y 						ELSIF (y.mode = Con) & (mant(y.a0) = 1) THEN y.a0 := log; y.typ := OCT.sinttyp; load(x); OCC.Put(F6, L+4, x, y) (*ASHi*) ELSE load(x); OCC.Put(F7, L+20H, x, y) (*MULi*) END ELSIF f IN realSet THEN loadF(x); OCC.Put(F11, 30H+L, x, y) (*MULf*) ELSIF f = Set THEN load(x); OCC.PutF4(2BH, x, y) (*ANDD*) ELSIF f # Undef THEN OCS.Mark(101) END | 2: IF f IN realSet THEN (*/*) loadF(x); OCC.Put(F11, 20H+L, x, y) (*DIVf*) ELSIF f IN intSet THEN convert2(x, OCT.realtyp); convert2(y, OCT.realtyp); OCC.Put(F11, 21H, x, y) (*DIVF*) ELSIF f = Set THEN load(x); OCC.PutF4(3BH, x, y) (*XORD*) ELSIF f # Undef THEN OCS.Mark(102) END | 3: IF f IN intSet THEN (*DIV*) IF (x.mode = Con) & (y.mode = Con) THEN IF y.a0 # 0 THEN x.a0 := x.a0 DIV y.a0; SetIntType(x) ELSE OCS.Mark(205) END ELSIF (y.mode = Con) & (mant(y.a0) = 1) THEN y.a0 := -log; y.typ := OCT.sinttyp; load(x); OCC.Put(F6, L+4, x, y) (*ASHi*) ELSE load(x); OCC.Put(F7, L+3CH, x, y) (*DIVi*) END ELSIF f # Undef THEN OCS.Mark(103) END | 4: IF f IN intSet THEN (*MOD*) IF (x.mode = Con) & (y.mode = Con) THEN IF y.a0 # 0 THEN x.a0 := x.a0 MOD y.a0; x.typ := y.typ ELSE OCS.Mark(205) END ELSIF (y.mode = Con) & (mant(y.a0) = 1) THEN y.a0 := ASH(-1, log); load(x); OCC.PutF4(L+8, x, y) (*BICi*) ELSE load(x); OCC.Put(F7, L+38H, x, y) (*MODi*) END ELSIF f # Undef THEN OCS.Mark(104) END | 5: IF y.mode # Coc THEN (*&*) IF y.mode = Con THEN IF y.a0 = 1 THEN setCC(y, 14) ELSE setCC(y, 15) END ELSIF y.mode <= Reg THEN OCC.PutF2(1CH, 1, y); setCC(y, 0) ELSE OCS.Mark(94); setCC(y, 0) END END ; IF x.mode = Con THEN IF x.a0 = 0 THEN OCC.FixLink(y.a1); OCC.FixLink(y.a2); setCC(y, 15) END ; setCC(x, 0) END; IF y.a2 # 0 THEN x.a2 := OCC.MergedLinks(x.a2, y.a2) END ; x.a0 := y.a0; x.a1 := y.a1 			| 6: IF f IN intSet THEN (*+*) IF (x.mode = Con) & (y.mode = Con) THEN INC(x.a0, y.a0); SetIntType(x) (*ovfl test missing*) ELSE load(x); add(L, x, y) 					END ELSIF f IN realSet THEN loadF(x); OCC.Put(F11, L, x, y) (*ADDf*) ELSIF f = Set THEN IF (x.mode = Con) & (y.mode = Con) THEN x.a0 := SYSTEM.VAL (LONGINT, SYSTEM.VAL(SET, x.a0) + SYSTEM.VAL(SET, y.a0)) ELSE load(x); OCC.PutF4(1BH, x, y) (*ORD*) END ELSIF f # Undef THEN OCS.Mark(105) END | 7: IF f IN intSet THEN (*-*) IF (x.mode = Con) & (y.mode = Con) THEN DEC(x.a0, y.a0); SetIntType(x) (*ovfl test missing*) ELSE load(x); sub(L, x, y) 					END ELSIF f IN realSet THEN loadF(x); OCC.Put(F11, 10H+L, x, y) (*SUBf*) ELSIF f = Set THEN load(x); OCC.PutF4(0BH, x, y) (*BICD*) ELSIF f # Undef THEN OCS.Mark(106) END | 8: IF y.mode # Coc THEN (*OR*) IF y.mode = Con THEN IF y.a0 = 1 THEN setCC(y, 14) ELSE setCC(y, 15) END ELSIF y.mode <= Reg THEN OCC.PutF2(1CH, 1, y); setCC(y, 0) ELSE OCS.Mark(95); setCC(y, 0) END END ; IF x.mode = Con THEN IF x.a0 = 1 THEN OCC.FixLink(y.a1); OCC.FixLink(y.a2); setCC(y, 14) END ; setCC(x, 0) END ; IF y.a1 # 0 THEN x.a1 := OCC.MergedLinks(x.a1, y.a1) END ; x.a0 := y.a0; x.a2 := y.a2 			| 9: IF f IN {Undef, Char..LInt, Set, NilTyp, Pointer, ProcTyp} THEN cmp(L, x, y); setCC(x, 0) ELSIF f IN realSet THEN OCC.Put(F11, 8+L, x, y); setCC(x, 0) ELSIF f = Bool THEN CompBool(0) ELSIF strings THEN CompStrings(0, TRUE) ELSE OCS.Mark(107) END |10: IF f IN {Undef, Char..LInt, Set, NilTyp, Pointer, ProcTyp} THEN cmp(L, x, y); setCC(x, 1) ELSIF f IN realSet THEN OCC.Put(F11, 8+L, x, y); setCC(x, 1) ELSIF f = Bool THEN CompBool(1) ELSIF strings THEN CompStrings(1, TRUE) ELSE OCS.Mark(107) END |11: IF f IN intSet THEN cmp(L, x, y); setCC(x, 6) ELSIF f = Char THEN cmp(0, x, y); setCC(x, 4) ELSIF f IN realSet THEN OCC.Put(F11, 8+L, x, y); setCC(x, 6) ELSIF strings THEN CompStrings(4, FALSE) ELSE OCS.Mark(108) END |12: IF f IN intSet THEN cmp(L, x, y); setCC(x, 13) ELSIF f = Char THEN cmp(0, x, y); setCC(x, 11) ELSIF f IN realSet THEN OCC.Put(F11, 8+L, x, y); setCC(x, 13) ELSIF strings THEN CompStrings(11, TRUE) ELSE OCS.Mark(108) END |13: IF f IN intSet THEN cmp(L, x, y); setCC(x, 12) ELSIF f = Char THEN cmp(0, x, y); setCC(x, 10) ELSIF f IN realSet THEN OCC.Put(F11, 8+L, x, y); setCC(x, 12) ELSIF strings THEN CompStrings(10, TRUE) ELSE OCS.Mark(108) END |14: IF f IN intSet THEN cmp(L, x, y); setCC(x, 7) ELSIF f = Char THEN cmp(0, x, y); setCC(x, 5) ELSIF f IN realSet THEN OCC.Put(F11, 8+L, x, y); setCC(x, 7) ELSIF strings THEN CompStrings(5, FALSE) ELSE OCS.Mark(108) END END END Op; PROCEDURE StPar1*(VAR x: OCT.Item; fctno: INTEGER); VAR f, L: INTEGER; s: LONGINT; y: OCT.Item; BEGIN f := x.typ.form; CASE fctno OF 				0: (*HALT*) IF (f = SInt) & (x.mode = Con) THEN IF x.a0 >= 20 THEN OCC.PutF1(0F2H); OCC.PutByte(x.a0) (*BPT*) ELSE OCS.Mark(218) END ELSE OCS.Mark(217) END ; x.typ := OCT.notyp | 1: (*NEW*) y.mode := Reg; IF f = Pointer THEN y.a0 := 0; OCC.PutF4(27H, y, x); x.typ := x.typ.BaseTyp; f := x.typ.form; IF x.typ.size > 7FFF80H THEN OCS.Mark(227) ELSIF f = Record THEN y.a0 := 1; x.mode := Var; x.lev := -x.typ.mno; x.a0 := x.typ.adr; OCC.PutF4(17H, y, x); OCC.PutF1(0E2H); OCC.PutByte(0) (*SVC 0*) ELSIF f = Array THEN y.a0 := 2; x.a0 := x.typ.size; x.mode := Con; x.typ := OCT.linttyp; OCC.PutF4(17H, y, x); OCC.PutF1(0E2H); OCC.PutByte(1) (*SVC 1*) ELSE OCS.Mark(111) END ELSE OCS.Mark(111) END ; x.typ := OCT.notyp | 2: (*CC*) IF (f = SInt) & (x.mode = Con) THEN IF (0 <= x.a0) & (x.a0 < 16) THEN setCC(x, x.a0) ELSE OCS.Mark(219) END ELSE OCS.Mark(217) END | 3: (*ABS*) y := x; L := lengcode[f]; IF f IN intSet THEN OCC.GetReg(x); OCC.Put(F6, 30H+L, x, y) (*ABSi*) ELSIF f IN realSet THEN OCC.GetFReg(x); OCC.Put(F11, 34H+L, x, y) (*ABSf*) ELSE OCS.Mark(111) END | 4: (*CAP*) y.mode := Con; y.typ := OCT.chartyp; y.a0 := 5FH; IF f = Char THEN load(x); OCC.PutF4(28H, x, y) (*ANDB*) ELSE OCS.Mark(111); x.typ := OCT.chartyp END | 5: (*ORD*) IF (f = Char) OR (f = Byte) THEN (*MOVZBW*) IF x.mode # Con THEN y := x; OCC.GetReg(x); OCC.Put(F7, 14H, x, y) END ELSE OCS.Mark(111) END ; x.typ := OCT.inttyp | 6: (*ENTIER*) IF f IN realSet THEN y := x; OCC.GetReg(x); OCC.Put(F9, lengcode[f]*4 + 3BH, x, y) (*FLOORfD*) ELSE OCS.Mark(111) END ; x.typ := OCT.linttyp | 7: (*SIZE*) IF x.mode = Typ THEN x.a0 := x.typ.size ELSE OCS.Mark(110); x.a0 := 1 END ; x.mode := Con; SetIntType(x) | 8: (*ODD*) IF f IN intSet THEN y.mode := Con; y.typ := OCT.sinttyp; y.a0 := 0; OCC.PutF4(34H, x, y) (*TBITB 0*) ELSE OCS.Mark(111) END ; setCC(x, 8) | 9: (*ADR*) IF f = DynArr THEN y := x; OCC.GetReg(x); OCC.DynArrAdr(x, y) 				ELSE loadAdr(x); x.mode := Reg END ; x.typ := OCT.linttyp | 10: (*MIN*) IF x.mode = Typ THEN x.mode := Con; CASE f OF 							Bool, Char: x.a0 := 0 | SInt: x.a0 := -80H | Int: x.a0 := -8000H | LInt: x.a0 := 80000000H | Real: x.a0 := 0FF7FFFFFH | LReal: x.a0 := 0FFFFFFFFH; x.a1 := 0FFEFFFFFH | Set: x.a0 := 0; x.typ := OCT.inttyp | Undef, NilTyp .. Record: OCS.Mark(111) END ELSE OCS.Mark(110) END | 11: (*MAX*) IF x.mode = Typ THEN x.mode := Con; CASE f OF 							Bool: x.a0 := 1 | Char: x.a0 := 0FFH | SInt: x.a0 := 7FH | Int: x.a0 := 7FFFH | LInt: x.a0 := 7FFFFFFFH | Real: x.a0 := 7F7FFFFFH | LReal: x.a0 := 0FFFFFFFFH; x.a1 := 7FEFFFFFH | Set: x.a0 := 31; x.typ := OCT.inttyp | Undef, NilTyp .. Record: OCS.Mark(111) END ELSE OCS.Mark(110) END | | 12: (*CHR*) IF ~(f IN {Undef, Byte, SInt, Int, LInt}) THEN OCS.Mark(111) END ; IF (x.mode = VarX) OR (x.mode = IndX) THEN load(x) END ; x.typ := OCT.chartyp | 13: (*SHORT*) IF f = LInt THEN (*range test missing*) IF (x.mode = VarX) OR (x.mode = IndX) THEN load(x) ELSIF x.mode = Con THEN SetIntType(x); IF x.typ.form = LInt THEN OCS.Mark(203) END END ; x.typ := OCT.inttyp ELSIF f = LReal THEN (*MOVLF*) y := x; OCC.GetFReg(x); OCC.Put(F9, 16H, x, y); x.typ := OCT.realtyp ELSIF f = Int THEN (*range test missing*) IF (x.mode = VarX) OR (x.mode = IndX) THEN load(x) ELSIF x.mode = Con THEN SetIntType(x); IF x.typ.form # SInt THEN OCS.Mark(203) END END ; x.typ := OCT.sinttyp ELSE OCS.Mark(111) END | 14: (*LONG*) IF f = Int THEN convert1(x, OCT.linttyp) ELSIF f = Real THEN convert3(x) ELSIF f = SInt THEN convert1(x, OCT.inttyp) ELSIF f = Char THEN y := x; OCC.GetReg(x); OCC.Put(F7, 18H, x, y); x.typ := OCT.linttyp (*MOVZBD*) ELSE OCS.Mark(111) END | 15: (*OVFL*) IF (f = Bool) & (x.mode = Con) THEN (*BICPSRB 10H*) OCC.PutF1(7CH); OCC.PutF1(SHORT(x.a0)*2 + 0A1H); OCC.PutF1(10H) ELSE OCS.Mark(111) END ; x.typ := OCT.notyp | 16,17: (*INC DEC*) IF x.mode >= Con THEN OCS.Mark(112) ELSIF ~(f IN intSet) THEN OCS.Mark(111) END | 18,19: (*INCL EXCL*) IF x.mode >= Con THEN OCS.Mark(112) ELSIF x.typ # OCT.settyp THEN OCS.Mark(111); x.typ := OCT.settyp END | 20: (*LEN*) IF (f # DynArr) & (f # Array) THEN OCS.Mark(131) END | 21: (*ASH*) IF f = LInt THEN load(x) ELSIF f IN intSet THEN loadX(x); x.typ := OCT.linttyp ELSE OCS.Mark(111) END | 22, 23: (*LSH ROT*) IF f IN {Char, SInt, Int, LInt, Set} THEN load(x) ELSE OCS.Mark(111) END | 24,25,26: (*GET, PUT, BIT*) IF (f IN intSet) & (x.mode = Con) THEN x.mode := Abs ELSIF f = LInt THEN IF (x.mode = Var) & (x.lev >= 0) THEN x.mode := Ind; x.a1 := 0 ELSE load(x); x.mode := RegI; x.a1 := 0 END ELSE OCS.Mark(111) END | 27: (*VAL*) IF x.mode # Typ THEN OCS.Mark(110) END | 28: (*SYSTEM.NEW*) IF (f = Pointer) & (x.mode < Con) THEN y.mode := Reg; y.a0 := 0; OCC.PutF4(27H, y, x); ELSE OCS.Mark(111) END | 29: (*COPY*) IF (((f=Array) OR (f=DynArr)) & (x.typ.BaseTyp.form = Char)) OR (f = String) THEN y.mode := Reg; y.a0 := 1; IF f = DynArr THEN OCC.DynArrAdr(y, x) 					ELSE OCC.PutF4(27H, y, x) 					END ELSE OCS.Mark(111) END | 30: (*MOVE*) IF f = LInt THEN y.mode := Reg; y.a0 := 1; OCC.PutF4(17H, y, x) 				ELSE OCS.Mark(111) END END END StPar1; PROCEDURE StPar2*(VAR p, x: OCT.Item; fctno: INTEGER); VAR f, L: INTEGER; y, z: OCT.Item; typ: OCT.Struct; BEGIN f := x.typ.form; IF fctno < 16 THEN OCS.Mark(64); RETURN END ; CASE fctno OF 				16, 17: (*INC DEC*) IF x.typ # p.typ THEN IF (x.mode = Con) & (x.typ.form IN intSet) THEN x.typ := p.typ ELSE OCS.Mark(111) END END ; L := lengcode[p.typ.form]; IF fctno = 16 THEN add(L, p, x) ELSE sub(L, p, x) END ; p.typ := OCT.notyp | 18: (*INCL*) Set0(y, x); OCC.PutF4(1BH, p, y); p.typ := OCT.notyp (*ORD*) | 19: (*EXCL*) Set0(y, x); OCC.PutF4(0BH, p, y); p.typ := OCT.notyp (*BICD*) | 20: (*LEN*) IF (x.mode = Con) & (f = SInt) THEN L := SHORT(x.a0); typ := p.typ; WHILE (L > 0) & (typ.form IN {DynArr, Array}) DO 						typ := typ.BaseTyp; DEC(L) END; IF (L # 0) OR ~(typ.form IN {DynArr, Array}) THEN OCS.Mark(132) ELSE IF typ.form = DynArr THEN p.mode := Var; p.typ := OCT.linttyp; INC(p.a0, typ.adr); load(p); OCC.PutF2(0FH, 1, p) (* ADDQD 1, p *) ELSE p := x; p.a0 := typ.n; SetIntType(p) END END ELSE OCS.Mark(111) END | 21, 22, 23: (*ASH LSH ROT*) IF f IN intSet THEN IF fctno = 21 THEN L := 4 ELSIF fctno = 22 THEN L := 14H ELSE L := 0 END ; IF (x.mode = VarX) OR (x.mode = IndX) THEN load(x) END ; x.typ := OCT.sinttyp; OCC.Put(F6, lengcode[p.typ.form]+L, p, x) 				ELSE OCS.Mark(111) END | 24: (*GET*) IF x.mode >= Con THEN OCS.Mark(112) ELSIF f IN {Undef..LInt, Set, Pointer, ProcTyp} THEN OCC.PutF4(lengcode[f]+14H, x, p) 				ELSIF f IN realSet THEN OCC.Put(F11, lengcode[f]+4, x, p) (*MOVf*) END ; p.typ := OCT.notyp | 25: (*PUT*) IF f IN {Undef..LInt, Set, Pointer, ProcTyp} THEN OCC.PutF4(lengcode[f]+14H, p, x) 				ELSIF f IN realSet THEN OCC.Put(F11, lengcode[f]+4, p, x) (*MOVf*) END ; p.typ := OCT.notyp | 26: (*BIT*) IF f IN intSet THEN OCC.PutF4(lengcode[f] + 34H, p, x) (*TBITi*) ELSE OCS.Mark(111) END ; setCC(p, 8) | 27: (*VAL*) x.typ := p.typ; p := x 			| 28: (*SYSTEM.NEW*) y.mode := Reg; y.a0 := 2; IF f = LInt THEN OCC.PutF4(17H, y, x) 				ELSIF f = Int THEN OCC.Put(F7, 1DH, y, x) (*MOVXWD*) ELSIF f = SInt THEN OCC.Put(F7, 1CH, y, x) (*MOVXBD*) ELSE OCS.Mark(111) END ; OCC.PutF1(0E2H); OCC.PutByte(1); (*SVC 1*) p.typ := OCT.notyp | 29: (*COPY*) IF ((f = Array) OR (f = DynArr)) & (x.typ.BaseTyp.form = Char) THEN y.mode := Reg; y.a0 := 2; y.a1 := 0; IF f = DynArr THEN p := x; OCC.DynArrAdr(y, x); y.a0 := 0; p.mode := Var; INC(p.a0, p.typ.adr); OCC.PutF4(17H, y, p) 					ELSE OCC.PutF4(27H, y, x); y.a0 := 0; p.mode := Con; p.typ := OCT.inttyp; p.a0:= x.typ.size-1; OCC.Put(F7, 19H, y, p); (*MOVZWD*) END; y.a0 := 4; OCC.PutF2(5FH, 0, y); (*MOVQD*) OCC.PutF1(14); OCC.PutF1(0); OCC.PutF1(6); (*MOVSB*) y.mode := RegI; y.a0 := 2; OCC.PutF2(5CH, 0, y) (*MOVQB*) ELSE OCS.Mark(111) END ; p.typ := OCT.notyp | 30: (*MOVE*) IF f = LInt THEN y.mode := Reg; y.a0 := 2; OCC.PutF4(17H, y, x) 				ELSE OCS.Mark(111) END END END StPar2; PROCEDURE StPar3*(VAR p, x: OCT.Item; fctno: INTEGER); VAR f: INTEGER; y: OCT.Item; BEGIN f := x.typ.form; IF fctno = 30 THEN (*MOVE*) y.mode := Reg; y.a0 := 0; IF f = Int THEN OCC.Put(F7, 1DH, y, x) 			ELSIF f = SInt THEN OCC.Put(F7, 1CH, y, x) 			ELSIF f = LInt THEN OCC.PutF4(17H, y, x) 			ELSE OCS.Mark(111) END ; OCC.PutF1(14); OCC.PutF1(0); OCC.PutF1(0); p.typ := OCT.notyp (*MOVSB*) ELSE OCS.Mark(64) END END StPar3; PROCEDURE StFct*(VAR p: OCT.Item; fctno, parno: INTEGER); BEGIN IF fctno >= 16 THEN IF (fctno = 16) & (parno = 1) THEN (*INC*) OCC.PutF2(lengcode[p.typ.form]+0CH, 1, p); p.typ := OCT.notyp ELSIF (fctno = 17) & (parno = 1) THEN (*DEC*) OCC.PutF2(lengcode[p.typ.form]+0CH, -1, p); p.typ := OCT.notyp ELSIF (fctno = 20) & (parno = 1) THEN (*LEN*) IF p.typ.form = DynArr THEN p.mode := Var; INC(p.a0, p.typ.adr); p.typ := OCT.linttyp; load(p); OCC.PutF2(0FH, 1, p) (*ADDQD 1 p*) ELSE p.mode := Con; p.a0 := p.typ.n; SetIntType(p) END ELSIF (parno < 2) OR (fctno = 30) & (parno < 3) THEN OCS.Mark(65) END ELSIF parno < 1 THEN OCS.Mark(65) END END StFct; BEGIN intSet := {SInt, Int, LInt}; realSet := {Real, LReal}; lengcode[Undef] := 0; lengcode[Byte] := 0; lengcode[Bool] := 0; lengcode[Char] := 0; lengcode[SInt] := 0; lengcode[Int] := 1; lengcode[LInt] := 3; lengcode[Real] := 1; lengcode[LReal] := 0; lengcode[Set] := 3; lengcode[String] := 0; lengcode[NilTyp] := 3; lengcode[ProcTyp] := 3; lengcode[Pointer] := 3; lengcode[Array] := 1; lengcode[DynArr] := 1; lengcode[Record] := 1 END OCE.

title: Oberon/V2/OCE


text:
Go Programming/Simple Web App

There are multiple packages in the standard library. One of those packages is called net/http. The package can be used to make simple web applications. Here is a simple example that will output Hello world! when localhost:8080 is visited.

You might see some new things that appeared.

As you see, the fmt package has been imported again. However, the net/http package has also been imported. A function called helloFunc is declared. The http.ResponseWriter type is used in the function to construct an HTTP response. The *http.Request is a pointer to a HTTP request received by a server or something be sent by a client. In this line, the string "Hello world!" is being written to the ResponseWriter in order for it to be displayed in the output. The main function has been declared with two actions. The handler function, helloFunc has been connected to the "/" route. Finally, the ListenAndServe has been called with a port that is "8080" and no router has been given to the second parameter.

Now, when the program is ran, Hello world! is expected to be shown on the website: localhost:8080.

title: Go Programming/Simple Web App