Difference between revisions of "Peano numbers"

From HaskellWiki
Jump to navigation Jump to search
 
(→‎Peano number values: update link to code.haskell.org)
(21 intermediate revisions by 7 users not shown)
Line 1: Line 1:
'''Peano numbers''' are a simple way of representing the natural numbers using only a zero value and a successor function. In Haskell it is easy to create a type of Peano number values, but they are more often used to create a set of [[phantom type]]s.
+
'''Peano numbers''' are a simple way of representing the natural numbers using only a zero value and a successor function. In Haskell it is easy to create a type of Peano number values, but since unary representation is inefficient, they are more often used to do [[type arithmetic]] due to their simplicity.
   
== Peano number values ==
+
== Overview ==
   
 
=== Peano number values ===
  +
  +
<haskell>
 
data Peano = Zero | Succ Peano
 
data Peano = Zero | Succ Peano
  +
</haskell>
  +
 
Here <hask>Zero</hask> and <hask>Succ</hask> are values (constructors). <hask>Zero</hask> has type <hask>Peano</hask>, and <hask>Succ</hask> has type <hask>Peano -> Peano</hask>. The natural number zero is represented by <hask>Zero</hask>, one by <hask>Succ Zero</hask>, two by <hask>Succ (Succ Zero)</hask> and so forth.
  +
  +
Here's a simple addition function:
  +
  +
<haskell>
  +
add Zero b = b
  +
add (Succ a) b = Succ (add a b)
  +
</haskell>
  +
  +
See an [http://code.haskell.org/~thielema/htam/src/Number/PeanoNumber.hs example implementation].
  +
  +
=== Peano number types ===
  +
  +
<haskell>
 
data Zero
 
data Succ a
  +
</haskell>
  +
 
Here <hask>Zero</hask> and <hask>Succ</hask> are types. <hask>Zero</hask> has kind <hask>*</hask>, and <hask>Succ</hask> has kind <hask>* -> *</hask>. The natural numbers are represented by types (of kind <hask>*</hask>) <hask>Zero</hask>, <hask>Succ Zero</hask>, <hask>Succ (Succ Zero)</hask> etc.
  +
  +
Arithmetic can be done using [[fundep]]s:
  +
  +
<haskell>
  +
class Add a b ab | a b -> ab
  +
instance Add Zero b b
  +
instance (Add a b ab) => Add (Succ a) b (Succ ab)
  +
</haskell>
  +
  +
Note that classes express relationships between types, rather than functions from type to type. Accordingly, with the instance declarations above one can add another fundep to the class declaration to get subtraction for free:
  +
  +
<haskell>
  +
class Add a b ab | a b -> ab, a ab -> b
  +
instance Add Zero b b
  +
instance (Add a b ab) => Add (Succ a) b (Succ ab)
  +
</haskell>
  +
  +
See [[type arithmetic]] for other functions and encodings.
  +
  +
== Applications ==
  +
  +
=== Lazy counting ===
  +
  +
The lazy nature of Peano numbers rehabilitates the use of list functions which count list elements.
  +
As described in [[Things to avoid#Don.27t_ask_for_the_length_of_a_list_when_you_don.27t_need_it|Things to avoid]]
  +
one should not write
  +
<haskell>
  +
length xs == 0
  +
</haskell>
  +
because <hask>length</hask> traverses the whole list and may take a long time doing so, although after you have seen only one, it is obvious that the list is not empty.
  +
The above expression can be simply replaced by <hask>null</hask>, but with Peano numbers you achieve the same
  +
<haskell>
  +
genericLength xs == Zero
  +
-- or
  +
genericLength xs == (0::Peano)
  +
</haskell>
  +
  +
The expression
  +
<haskell>
  +
length xs == length ys
  +
</haskell>
  +
is harder to make lazy without Peano numbers.
  +
With them (and an appropriate <hask>Num</hask> instance) this becomes rather simple, because
  +
<haskell>
  +
genericLength xs == (genericLength ys :: Peano)
  +
</haskell>
  +
traverses only as many list nodes as are in the shorter list.
  +
  +
=== Equation solving ===
   
  +
Lazy Peano numbers can also be used within "[[Tying the Knot]]" techniques.
Here <tt>Zero</tt> and <tt>Succ</tt> are values (constructors). <tt>Zero</tt> has type <tt>Peano</tt>, and <tt>Succ</tt> has type <tt>Peano -> Peano</tt>. The natural number zero is represented by <tt>Zero</tt>, one by <tt>Succ Zero</tt>, two by <tt>Succ Succ Zero</tt> and so forth.
 
  +
There is a [http://darcs.haskell.org/unique-logic/haskell98/src/UniqueLogic/Lazy/Peano.hs package] for determining the right order for solving equations,
  +
where an equation is only solved if only one of its variables is still indeterminate.
   
== Peano number types ==
 
   
  +
== See also ==
data Zero
 
   
  +
See example implementations:
data Succ a
 
  +
* [http://darcs.haskell.org/htam/src/Number/PeanoNumber.hs using standard Prelude]
  +
* using [[Numeric Prelude]] [http://darcs.haskell.org/numericprelude/src/Number/Peano.hs type classes]
   
  +
[[Category:Mathematics]]
Here <tt>Zero</tt> and <tt>Succ</tt> are types. <tt>Zero</tt> has kind <tt>*</tt>, and <tt>Succ</tt> has kind <tt>* -> *</tt>. The natural numbers are represented by types (of kind <tt>*</tt>) <tt>Zero</tt>, <tt>Succ Zero</tt>, <tt>Succ Succ Zero</tt> etc.
 
  +
[[Category:Idioms]]
  +
[[Category:Glossary]]

Revision as of 12:07, 24 October 2014

Peano numbers are a simple way of representing the natural numbers using only a zero value and a successor function. In Haskell it is easy to create a type of Peano number values, but since unary representation is inefficient, they are more often used to do type arithmetic due to their simplicity.

Overview

Peano number values

 data Peano = Zero | Succ Peano

Here Zero and Succ are values (constructors). Zero has type Peano, and Succ has type Peano -> Peano. The natural number zero is represented by Zero, one by Succ Zero, two by Succ (Succ Zero) and so forth.

Here's a simple addition function:

add Zero b = b
add (Succ a) b = Succ (add a b)

See an example implementation.

Peano number types

data Zero
data Succ a

Here Zero and Succ are types. Zero has kind *, and Succ has kind * -> *. The natural numbers are represented by types (of kind *) Zero, Succ Zero, Succ (Succ Zero) etc.

Arithmetic can be done using fundeps:

class Add a b ab | a b -> ab
instance Add Zero b b
instance (Add a b ab) => Add (Succ a) b (Succ ab)

Note that classes express relationships between types, rather than functions from type to type. Accordingly, with the instance declarations above one can add another fundep to the class declaration to get subtraction for free:

class Add a b ab | a b -> ab, a ab -> b
instance Add Zero b b
instance (Add a b ab) => Add (Succ a) b (Succ ab)

See type arithmetic for other functions and encodings.

Applications

Lazy counting

The lazy nature of Peano numbers rehabilitates the use of list functions which count list elements. As described in Things to avoid one should not write

length xs == 0

because length traverses the whole list and may take a long time doing so, although after you have seen only one, it is obvious that the list is not empty. The above expression can be simply replaced by null, but with Peano numbers you achieve the same

genericLength xs == Zero
-- or
genericLength xs == (0::Peano)

The expression

length xs == length ys

is harder to make lazy without Peano numbers. With them (and an appropriate Num instance) this becomes rather simple, because

genericLength xs == (genericLength ys :: Peano)

traverses only as many list nodes as are in the shorter list.

Equation solving

Lazy Peano numbers can also be used within "Tying the Knot" techniques. There is a package for determining the right order for solving equations, where an equation is only solved if only one of its variables is still indeterminate.


See also

See example implementations: