Search                        Top                                  Index
/*
TEACH TEACHNUMS                                 Aaron Sloman 10 Aug 2009

This is a DRAFT teach file. Comments and suggestions welcome.

It may be too difficult for some younger children, though some of the
early ideas could be presented by a teacher using a computer, with
pupils being asked to make suggestions about how things should work.

More advanced learners (especially potential mathematical high fliers)
could work through this file themselves, trying out the suggested
procedure definitions then exploring alternatives, and finally trying to
meet the challenges presented at the end, e.g. extending these ideas to
negative numbers, and other extensions.

Regarding negative numbers, teachers may find it useful to read:

Pamela Liebeck,
    Scores and Forfeits: An Intuitive Model for Integer Arithmetic,
    Educational Studies in Mathematics,
    Vol 21, No 3, June, 1990, pp. 221--239,

[Available via JSTOR to subscribing institutions]

CONTENTS - (Use <ENTER> g to access required sections)

 -- Introduction
 -- A myth about computers
 -- Using bit-patterns in two-element links chained to form lists
 -- Doing arithmetic on lists of x's.
 -- First procedure: a number recognizer
 -- A procedure for adding two nums
 -- A procedure to subtract a number from another
 -- Another version, subnums2 using the pattern matcher
 -- Multiplication as repeated addition
 -- Some predicates for comparing numbers
 -- -- samenum checks whether two numbers are the same
 -- -- bigger checks whether a number is bigger than another
 -- -- between checks whether a number is between two others
 -- A procedure to divide one number into another
 -- A hard problem: how to represent and operate on negative numbers
 -- Another hard problem: how to divide 4 by 7 and produce a fraction
 -- Introducing 'place' notation to compress number representations
 -- Can you use numbers for counting?
 -- -- Try problem (a)
 -- -- Try problem (b)
 -- Introducing numerals
 -- How about using place notation with number names?
 -- More information

-- Introduction

In this teach file we introduce the idea of representing numbers as
lists of 'x's and operations on numbers such as addition, subtraction
and multiplication as operations on lists. The file gets to the point
where new puzzles arise regarding how to deal with negative numbers.

Working out how to do that is left as an exercise (for teachers and
learners). There is no one right answer: learners should explore
different types of solution.

-- A myth about computers ---------------------------------------------

It is often said that computers operate primarily on numbers and that
everything else computers do is built on top of those operations.

This is not correct. Computers operate on 'bit-patterns', i.e. patterns
made of collections of switches that can be on or off. These can be
represented by strings made up of '1's and '0's, e.g.

    000111000111000111
    000010011000111001101111

The fact that we use '0' and '1', is misleading. We could have used 'X'
and 'Y', e.g.

    XXXYYYXXXYYYXXXYYY
    XXXXYXXYYXXXYYYXXYYXYYYY

Any two symbols can be used in bit-patterns.

One of many things that can be done using bit patterns is representing
locations in memory in the computer, and also representing printable
symbols.

For now the details are not important.

-- Using bit-patterns in two-element links chained to form lists ------

It is very often useful to store information in structures that are all
built out of elementary structures containing only two adjacent
locations in memory. These are called 'pairs' in Pop-11.

The first location of a pair may store some bit pattern that represents
a letter for example 'x' or 'y', or a word, e.g. 'the' or 'cat', or
anything else (e.g. a number 3769).

The second location can store a bit pattern that specifies the location
of another pair. When several pairs are 'joined up' in a series to form
a chain, because each pair points to the next pair, then they are
sometimes referred to as 'links', making up a chain, or list.

For example the list of words

    [how now brown cow]

could be represented as chained links, as follows, where each asterisk
'*' represents a bit-pattern that specifies the location of the next
link, and 'NIL' at the end means there is not another link:

     .---.   .---.---.   .---.---.   .-----.---.   .---.---.
     | *---->|how| *---->|now| *---->|brown| *---->|cow|NIL|
     .---.   .---.---.   .---.---.   .-----.---.   .---.---.

The first asterisk represents a bit-pattern that could be stored in
various places, specifying where to find this list.

This diagram suggests that the links are all stored close together, and
in the order shown, but that is not required for the system to work.

There are many more details concerning how lists are represented in
computers, but we shall ignore them as we want to explore ways of using
lists to represent numbers.

Anyone wanting to know more about what lists are, how they are
implemented in Pop-11, and which notations and commands are available to
construct and operate on them, can look at

    TEACH LISTS
    TEACH WAL
    TEACH MATCHES

and many 'teach' files that use lists and the pattern matcher, e.g.

    TEACH RIVER
    TEACH RESPOND

Below we introduce the idea of using a list of 'x's to represent a
number. We then have to define arithmetical operations, like addition,
multiplication, subtraction and division using operations on lists.

This file assumes that you have already had some practice writing simple
Pop-11 programs and know, for example, that if L is a list, then hd(L)
is the first element of L (its 'head') and tl(L) is a list (the 'tail'
of L) containing everything in L except the first element.

So
    hd([how now brown cow]) is the word "how"

    tl([how now brown cow]) is the list [now brown cow]

The operator "<>" can be used to join two lists together, or more
precisely to produce a new list that starts with the elements of the
first list and then has a tail containing the second list.

For example:

    [how now] <> [brown cow] produces [how now brown cow]

-- Doing arithmetic on lists of x's. ----------------------------------

In what follows we present some pop-11 procedures that can operate on
lists of x's in order to perform arithmetic operations. You will find
each procedure presented with some documentation preceding it, saying
what its name is, what inputs it takes, what output it takes, what it is
for and giving some test examples.

The tests can be run after the procedures are compiled. If you change
any of the procedure definitions you should run the tests again.

The procedure headers are produced using a command in the poplog editor
Ved, namely ENTER procheader, whose use is explained in
    HELP * VED_PROCHEADER

the procedures defined below are

    define isnum(item) -> boole;
        check whether item is a number and return true or false

    define addnums(num1, num2) -> sum;

        check whether num1 and num2 are numbers and if so return a
        new number which is their sum, otherwise mishap

    define subnums(num1, num2) -> diff;

        if num1 and num2 are numbers return a number that is
        their difference

    define subnums2(num1, num2) -> diff;
        another way of defining subnums

    define mult(num1, num2) -> product;

        if num1 and num2 are numbers return a number that is
        the result of multiplying num1 by num2

The next three are predicates for testing a relation between two or
three numbers. They all return a boolean value, i.e. true or false.

    define samenum(num1, num2) -> boole;
        true if the numbers are the same

    define bigger(num1, num2) -> boole;
        true if num1 is bigger than num2

    define between(num1, num2, num3) -> boole;
        true if num1 is between num2 and num3

Returning to arithmetical operators:

    define divide(num1, num2) -> (remainder, quotient);

        divide num1 by num2 and return the remainder and the quotient
        (num1 is the dividend, num2 the divisor)

The file ends with a challenge to extend these ideas to negative numbers
and some other challenges.


-- First procedure: a number recognizer -------------------------------

We need a number recognizer, which will be used in many other procedures
to check that they have been given a list, and failing that to produce
an error message (or MISHAP message in Pop-11).

We can define a number recognizer procedure as follows. It checks that
it is given a list, and that the list contains only occurrences of the
word "x".

It returns the boolean true or the boolean false, depending on what it
finds.

A first problem is whether the empty list should be used to represent a
number. An obvious answer is that it should represent the number 0.

We shall take that option below, but you could consider whether the
program could be changed so as not to allow the empty list.
*/

/*
PROCEDURE: isnum (item) -> boole
INPUTS   : item is anything
OUTPUTS  : boole is a truth-value (boolean)
USED IN  : Many procedures below.
CREATED  : 30 May 2009
PURPOSE  : Recognize a numeral in the form of a
           list that is either empty, i.e. [] or contains only
           occurrences of the word "x", e.g. [x] [x x x]

;;; specify some tests that will be used to check that the procedure
;;; works
TESTS:

isnum([x x x]) =>
** <true>

isnum([]) =>
** <true>

isnum([y y y]) =>
** <false>

isnum([xx]) =>
** <false>

isnum(99) =>
** <false>

*/

define isnum(item) -> boole;

    lvars L;

    ;;; if the list is empty
    if islist(item) and item matches []
    ;;; or the list starts with "x" followed by a number list
    or (islist(item) and item matches ![x ??L:isnum])
    then
        true
    else
        false
    endif ->  boole;
enddefine;


/*
-- A procedure for adding two nums ------------------------------------
*/

/*
PROCEDURE: addnums (num1, num2) -> sum
INPUTS   : num1, num2
  Where  :
    num1 is a num
    num2 is a num
OUTPUTS  : sum is a num
USED IN  : several procedures below
CREATED  : 30 May 2009
PURPOSE  : add two numbers (as lists) returning the sum (as a list).
           It should produce a mishap if given non-numbers.

TESTS:

addnums([], []) =>
** []

addnums([x], []) =>
** [x]

addnums([], [x]) =>
** [x]

addnums([x x], [x x x]) =>
** [x x x x x]

addnums([x x], [y y]) =>
;;; MISHAP - Nums needed for addnums
;;; INVOLVING:  [y y]
;;; FILE     :  /home/axs/popd/teachnums.p
;;; DOING    :  addnums runproc


;;; this should also produce a mishap (why?)

addnums([xx], [xxx]) =>
;;; MISHAP - Nums needed for addnums
;;; INVOLVING:  [xx]
;;; FILE     :  /home/axs/popd/teachnums.p
;;; DOING    :  addnums runproc

*/

define addnums(num1, num2) -> sum;

    ;;; first check that num1 and num2 satisfy isnum
    unless isnum(num1) then
        mishap('Nums needed for addnums', [^num1]);
    endunless;

    unless isnum(num2) then
        mishap('Nums needed for addnums', [^num2]);
    endunless;

    ;;; now we know they are both nums, so we can add them

    ;;; if either num1 or num2 is empty use the other as the result

    if num1 matches [] then
        num2 -> sum
    elseif num2 matches [] then
        num1 -> sum
    else
        ;;; add an "x" to num1 and reduce one from num2
        ;;; and add the two resulting lists
        addnums([ x ^^num1], tl(num2)) -> sum
    endif
enddefine;

;;; exercise: try defining a version of this using the Pop-11 concatenator
;;; operator <>

/*
-- A procedure to subtract a number from another ----------------------
*/

/*
PROCEDURE: subnums (num1, num2) -> diff
INPUTS   : num1, num2
  Where  :
    num1 is a number
    num2 is a number
OUTPUTS  : diff is a number
USED IN  : ???
CREATED  : 21 Jun 2009
PURPOSE  : ???
    if num1 is bigger than or equal to num2 then return a number which
    when added to num2 gives num1

TESTS:

subnums( [], [] ) =>
** []

subnums( [x], [] ) =>
** [x]

subnums( [], [x] ) =>

;;; MISHAP - subnums cannot subtract from zero
;;; INVOLVING:  [] [x]
;;; FILE     :  /home/axs/popd/teachnums.p
;;; DOING    :  subnums runproc

subnums( [x x x], [x x x x] ) =>

;;; MISHAP - subnums cannot subtract from zero
;;; INVOLVING:  [] [x]
;;; FILE     :  /home/axs/popd/teachnums.p
;;; DOING    :  subnums(*4) runproc


subnums( [x x x x], [x x x x] ) =>
** []
*/

define subnums(num1, num2) -> diff;

    if isnum(num1) and isnum(num2) then
        if num2 matches [] then
            num1 -> diff
        elseif num1 matches [] then
        mishap('subnums cannot subtract from zero', [^num1 ^num2]);
        else
            ;;; subtract an "x" from both and return the difference
            subnums(tl(num1), tl(num2)) -> diff
        endif
    else
        mishap('Nums needed for subnums', [^num1 ^num2]);
    endif;
enddefine;

/*
-- Another version, subnums2 using the pattern matcher ----------------
*/

/*
PROCEDURE: subnums2 (num1, num2) -> diff
INPUTS   : num1, num2
  Where  :
    num1 is a number
    num2 is a number
OUTPUTS  : diff is a number
USED IN  : ???
CREATED  : 21 Jun 2009
PURPOSE  : ???
    if num1 is bigger than or equal to num2 then return a number which
    when added to num2 gives num1

TESTS:

subnums2( [], [] ) =>
** []

subnums2( [x], [] ) =>
** [x]

subnums2( [], [x] ) =>
;;; MISHAP - Cannot subtract bigger number from smaller
;;; INVOLVING:  [] [x]
;;; FILE     :  /home/axs/popd/teachnums.p
;;; DOING    :  subnums2 runproc

subnums2( [x x x], [x] ) =>
** [x x]

subnums2( [x x x], [x x x x] ) =>
;;; MISHAP - Cannot subtract bigger number from smaller
;;; INVOLVING:  [x x x] [x x x x]
;;; FILE     :  /home/axs/popd/teachnums.p
;;; DOING    :  subnums2 runproc

subnums2( [x x x x], [x x x x] ) =>
** []

subnums2( [x x x x x x x x], [x x x x] ) =>
** [x x x x]
*/


define subnums2(num1, num2) -> diff;

    if isnum(num1) and isnum(num2) then
        if num1 matches ![??diff ^^num2] then
            ;;; nothing else to do
        else
            mishap('Cannot subtract bigger number from smaller', [^num1 ^num2])
        endif
    else
        mishap('Nums needed for subnums', [^num1 ^num2]);
    endif;
enddefine;



/*
-- Multiplication as repeated addition --------------------------------
*/

/*
PROCEDURE: mult (num1, num2) -> product
INPUTS   : num1, num2
  Where  :
    num1 is a num
    num2 is a num
OUTPUTS  : product is a num
USED IN  : ???
CREATED  : 30 May 2009
PURPOSE  : multiply two numbers (as lists) returning the product

TESTS:

mult([], []) =>
** []

mult([], [x x x x]) =>
** []

mult([x x x x], []) =>
** []

mult([x x x x], [x]) =>
** [x x x x]

mult([x], [x x x x]) =>
** [x x x x]

mult([x x], [x x x x]) =>
** [x x x x x x x x]

*/

define mult(num1, num2) -> product;
    if isnum(num1) and isnum(num2) then

        if num1 matches [] then
            [] -> product
        elseif num2 matches [] then
            [] -> product
        else

            [] -> product;
            until num2 matches [] do
                addnums(num1, product) -> product;
                tl(num2) -> num2;
            enduntil;
        endif
    else
        mishap('Nums needed for product', [^num1 ^num2]);
    endif;
enddefine;

;;; NOTE:
;;; A substantial chunk of the code in this procedure is redundant
;;; and can be removed, because of unobvious duplication.
;;; Which lines can be removed without changing the behaviour?
;;; Explain why?


/*
-- Some predicates for comparing numbers ------------------------------

-- -- samenum checks whether two numbers are the same
*/

/*
PROCEDURE: samenum (num1, num2) -> boole
INPUTS   : num1, num2
  Where  :
    num1 is a number
    num2 is a number
OUTPUTS  : boole is a boolean
USED IN  : divide
CREATED  : 10 Aug 2009
PURPOSE  : Testing numbers for equality

        true if the numbers are the same

TESTS:

samenum([], []) =>
** <true>

samenum([x], [x]) =>
** <true>

samenum([xx], [xx]) =>

;;; MISHAP - Nums needed for samenum
;;; INVOLVING:  [xx] [xx]
;;; FILE     :  /home/axs/popd/teachnums.p
;;; DOING    :  samenum runproc

samenum([x x], [x x]) =>
** <true>

samenum([x x x], [x]) =>
** <false>

samenum([], [x x]) =>
** <false>

*/

define samenum(num1, num2) -> boole;

    if isnum(num1) and isnum(num2) then

        num1 matches num2 -> boole

    else

        mishap('Nums needed for samenum', [^num1 ^num2]);

    endif
enddefine;


/*
-- -- bigger checks whether a number is bigger than another
*/

/*
PROCEDURE: bigger (num1, num2) -> boole
INPUTS   : num1, num2
  Where  :
    num1 is a num
    num2 is a num
OUTPUTS  : boole is a boolean
USED IN  : divide
CREATED  : 30 May 2009
PURPOSE  : determine whether num1 is bigger than num2

TESTS:

bigger([], []) =>
** <false>

bigger([x], []) =>
** <true>
bigger([], [x]) =>
** <false>

bigger([x x], [x x]) =>
** <false>

bigger([x x x], [x x]) =>
** <true>

bigger([x x x x x], [x x]) =>
** <true>

bigger([x x], [x x x x]) =>
** <false>


bigger([xx], [xxxx]) =>

;;; MISHAP - Nums needed for samenum
;;; INVOLVING:  [xx] [xxxx]
;;; FILE     :  /home/axs/popd/teachnums.p
;;; DOING    :  samenum bigger runproc


*/

define bigger(num1, num2) -> boole;
    ;;; note: we don't need to test that num1 and num2 are
    ;;; numbers, ad samenum does that

    if samenum(num1, num2) then
        false -> boole
    elseif num1 matches []  then
        false -> boole
    elseif num2 matches [] then
        true -> boole
    else bigger(tl(num1), tl(num2)) -> boole
    endif

enddefine;


/*
-- -- between checks whether a number is between two others
*/

/*
PROCEDURE: between (num1, num2, num3) -> boole
INPUTS   : num1, num2, num3
  Where  :
    num1 is a number
    num2 is a number
    num3 is a number
OUTPUTS  : boole is a boolean
USED IN  :
CREATED  : 21 Jun 2009
PURPOSE  : Check whether num1 is between num2 and num3
           in ascending or descending order

TESTS:

between([x], [x], [x]) =>
** <false>

between([x x], [x], []) =>
** <false>

between([x], [x x], []) =>
** <true>

between([x x], [x], [x x x]) =>
** <true>

between([x x], [x x], [x x x]) =>
** <false>
*/

define between(num1, num2, num3) -> boole;

    (bigger(num3, num1) and bigger(num1, num2))
    or
    (bigger(num2, num1) and bigger(num1, num3))
        -> boole

enddefine;


/*
-- A procedure to divide one number into another ----------------------
*/

/*
PROCEDURE: divide (num1, num2) -> (remainder, quotient);
INPUTS   : num1, num2
  Where  :
    num1 is a number (the dividend)
    num2 is a number (the divisor)
OUTPUTS  : remainder, quotient
  Where  :
    remainder is a number
    quotient is a number
USED IN  : ???
CREATED  : 21 Jun 2009
PURPOSE  : given two numbers num1, num2, divide num1 by num2 and
    return quotient and remainder

    quotient is the number of times num2 goes into num1

    remainder is the remainder after dividing num2 into num1

    (The remainder should be less than num2).

TESTS:

divide([], []) =>
;;; MISHAP - Cannot divide [] into []
;;; FILE     :  /home/axs/popd/teachnums.p
;;; DOING    :  divide runproc

;;; do the next two give reasonable answers?
divide([], [x]) =>
** [] []

divide([], [x x]) =>
** [] []

divide([x], []) =>
;;; MISHAP - Cannot divide [] into [x]
;;; FILE     :  /home/axs/popd/teachnums.p
;;; DOING    :  divide runproc

divide([x], [x]) =>
** [] [x]

divide([x x x x], [x x x x]) =>
** [] [x]

divide([x x x x], [x x]) =>
** [] [x x]

divide([x x x x x x x], [x x x]) =>
** [x] [x x]

divide([x x x x x x x x x], [x x x]) =>
** [] [x x x]

*/


define divide(num1, num2) -> (remainder, quotient);

    ;;; we don't need to check that they are numbers as
    ;;; bigger and samenum will do that

    if num2 == [] then
        mishap('Cannot divide [] into ' >< num1, []);
    elseif bigger(num2, num1) then
        [] -> quotient; num1 -> remainder
    elseif samenum(num1, num2) then
        [x] -> quotient; [] -> remainder
    else
        divide(subnums(num1, num2), num2) -> (remainder, quotient);
        addnums([x], quotient) -> quotient;
    endif;

enddefine;

/*
-- A hard problem: how to represent and operate on negative numbers ---
*/

/*
What should subnums do if the second number is larger than the first?

subnums([x x], [x x x]) =>

At present it gives this mysterious error message (which could be
modified of course):

    ;;; MISHAP - subnums cannot subtract from zero
    ;;; INVOLVING:  [] [x]
    ;;; FILE     :  /home/axs/popd/teachnums.p
    ;;; DOING    :  subnums(*3) runproc


You have been taught that the result of subtracting 3 from 2 should be a
negative number.

But what is a negative number?

How can you represent negative numbers using lists?

How should they be added, subtracted or multiplied?

Why should multiplying two negative numbers give a positive number?

Try to find ways of extending this package that are not totally
arbitrary and give a sensible interpretation of negative numbers.

If you come up with a suggestion please write to me about it (email
address at end of this file).

THERE IS NO UNIQUE RIGHT ANSWER
If you find an answer feel free to email me about it (address at bottom
of file), or post it on the comp.lang.pop forum.

You may find this paper by Pamela Liebeck relevant, if you can get hold
of it.

Pamela Liebeck,
    Scores and Forfeits: An Intuitive Model for Integer Arithmetic,
    Educational Studies in Mathematics,
    Vol 21, No 3, June, 1990, pp. 221--239,

Available on JSTOR here from subscribing academic institutions:
http://links.jstor.org/sici?sici=0013-1954%28199006%2921%3A3%3C221%3ASAFAIM%3E2.0.CO%3B2-N

*/

/*
-- Another hard problem: how to divide 4 by 7 and produce a fraction --
*/

/*
At present dividing a number by another number using the procedure
divide, defined above, gives a remainder and a quotient, as in these
examples:

    divide([x x x x x x x x], [x x x])=>
    ** [x x] [x x]

    divide([x x x x x x x x], [x x x x])=>
    ** [] [x x]

    divide([x x x x x x x x], [x x x x x])=>
    ** [x x x] [x]

    divide([x x], [x x x])=>
    ** [x x] []

    divide([x x x], [x x x x x])=>
    ** [x x x] []

Can you think of a way of changing the procedure divide(num1, num2), so
that instead of producing two numbers as its result it produces a single
object that can be thought of as a ratio (num1/num2).

The way you represent ratios should have the property that if you divide
num1 by num2 to get a ratio, then if you multiply that ratio by num2
you should get back to num1.

Can you make this work with negative as well as positive numbers.

The key idea is to think of a good way to represent ratios so that they
preserve all the required information, but have no redundant
information.

If you come up with a suggestion please write to me about it (email
address at end of this file).

THERE IS NO UNIQUE RIGHT ANSWER
If you find an answer feel free to email me about it (address at bottom
of file), or post it on the comp.lang.pop forum.
*/

/*
-- Introducing 'place' notation to compress number representations ----
*/

/*
If you use the notation developed here to represent numbers you will
soon realise that it is analogous to representing numbers by sequences
of strokes:

    | || ||| |||| ||||| ||||||

In principle any number, no matter how large, could be represented
either as a sequence of strokes, or as a list of x's. However this can
get very unwieldy for very large numbers. E.g. this is how the number
217 could look (with the list 'folded' to fit within a reasonable width:

   [x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
    x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
    x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
    x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
    x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
    x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x]

And this is how it could look using the stroke notation without spaces:

    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
    ||||||||||||||||

Compare that with the brevity of using three digits in  "217". This
works because the numbers are interpreted as

    keep the right most number
    add 10 times the number next left
    add 100 times the number next left
    .....

giving 7 + 10x1 + 100x2, or, if you prefer 2x100 + 10x1 + 7

Try working out a way to get a comparable compression using lists of x's
so that instead of a number like 217 being represented by one long list
of x's it is represented by three much shorter lists.

If you can develop such a notation try designing and testing some
procedures to convert between the above simple-minded list notation and
a place-based notation.

Also modify the procedures for adding, subtracting, multiplying and
dividing so that they can handle numbers represented in the new way.

THERE IS NO UNIQUE RIGHT ANSWER
If you find an answer feel free to email me about it (address at bottom
of file), or post it on the comp.lang.pop forum.
*/

/*
-- Can you use numbers for counting? ----------------------------------
*/

/*
(a) If I give you a list of words, and ask you how many there are, you
can point at them in turn as you recite number names, and when you get
to the end you can announce the final name as the answer to the 'how
many' question.

(b) Alternatively if I give you a list of words and ask you to give me a
list containing the first three words, or the first nine words, you can
count along the list until you get to the number specified, and make a
list of all the words you have counted.
*/

/*
-- -- Try problem (a)
*/

/*
Can you define a procedure how_many that performs the first task?

It is useful to use the fact that in Pop-11, code run in brackets like
this will create a list of the values produced in the code:

    [% .... %]

That construct could be used in a how_many procedure:
*/

define how_many(list) -> number;

    lvars item;

    ;;; go through the list and create a new one representing a number
    ;;; of the types used above.

    [%
    for item in list do

        ;;;; what exactly ???

    endfor
    %] -> number;

enddefine;

/*
;;; Test it thus (and define some more tests of your own)

    how_many([ the hat ]) =>

;;; should produce

    ** [x x]

whereas

    how_many([the man with a hat is blind as a bat ]) =>

;;; should produce

    ** [x x x x x x x x x x]

;;; What should this do?

    how_many([ ]) =>

*/

/*
-- -- Try problem (b)
*/

/*
Can you define a procedure count_out that performs the second task,
namely to produce a specified number of elements from a list.
*/

define count_out(items, number) -> list;

    ;;; what should go in here?

    ;;; you need a look to generate the numbers, one at a time,
    ;;; and as you do that you save an item from the list items.

    ;;; when you generate the target number given, the program can stop
    ;;; counting and return the list of saved items.

enddefine;


/*
;;; Test it thus (and define some more tests of your own)

    ;;; save a list of words for re-use
    vars words = [the man with a hat is blind as a bat];

    count_out(words, [x x]) =>

should produce

    ** [the man]

    count_out(words, [x x x x x]) =>

should produce

    ** [the man with a hat]

What should this do ?

    count_out(words, []) =>
*/

/*
-- Introducing numerals -----------------------------------------------
*/

/*
There are many things we use numbers for which would be very clumsy if
we were to use lists of 'x's as names. So it would be useful to have
Pop-11 words as names, providing a short hand notation. E.g.

    "one"   could be a name for [ x ]
    "two"   could be a name for [ x x ]
    "three" could be a name for [ x x x]
    "four"  could be a name for [ x x x x ]

and so on.

Can you find a way of setting up a mapping between the words and the
numbers, where the numbers are represented as lists of 'x's?

If you do that, how could you modify the previous two definitions so
that

    how_many([ the hat ]) =>

produces
    ** two

and

    count_out(words, "five") =>

produces

    ** [the man with a hat]
*/

/*
-- How about using place notation with number names? ------------------
*/

/*
Could you produce a program that understands the words

    nought one two .... nine

and then can interpret lists of those words as representing numbers in
the usual decimal way, e.g.

    what_number([three]) =>

should produce

    [x x x]

    what_number([three five]) =>

should produce a list of 35 'x's

    [x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x]

    what_number([three five nine]) =>

should produce a list of 359 'x's, and so on.

What should these produce

    what_number([three five nought]) =>

    what_number([three nought five]) =>


    what_number([nought three five]) =>

    what_number([nought nought three five]) =>
*/


/*
-- More information ---------------------------------------------------


For more information on poplog see
    http://www.cs.bham.ac.uk/research/projects/poplog/freepoplog.html

There is a section on teaching using Pop-11
    http://www.cs.bham.ac.uk/research/projects/poplog/freepoplog.html#teaching

There is a Pop-11 primer here:
    http://www.cs.bham.ac.uk/research/projects/poplog/primer/

========
Aaron Sloman
Email: A.Sloman@cs.bham.ac.uk
http://www.cs.bham.ac.uk/~axs

--- ?????/teachnums.p
--- Copyright University of Birmingham 2009. All rights reserved.
--- See http://www.cs.bham.ac.uk/research/projects/poplog/copyright.html

*/