\( % Latex Preamble definitions here (mostly usepackage) \usepackage% %[dvipsnames] {xcolor} % make sure this is before the loading font packages \newcommand\hmmax{0} \newcommand\bmmax{0} \usepackage{amssymb} \usepackage{amsmath} \usepackage{mathtools} \usepackage %[dvipsnames] {graphicx} \usepackage{float} %\usepackage[numbers]{natbib} \usepackage[document]{ragged2e} % % enumitem doesn't seem to work with beamer %\usepackage[inline]{enumitem} \usepackage{wrapfig} \usepackage{stackrel} % extensible arrows \usepackage{extpfeil} % \usepackage{trfrac} \usepackage{amsthm} \usepackage{tikz} \usepackage{tikz-cd} \usepackage{tikz} \usepackage{tikz-qtree} \usetikzlibrary{automata, positioning, arrows, shapes.geometric} \usepackage{turnstile} \usepackage{comment} %https://tex.stackexchange.com/questions/21334/is-there-a-package-that-has-the-clockwise-gapped-circle-arrow-in-it % \usepackage{mathbx} \usepackage{datetime} \usepackage{datetime2} %% Also See %% http://u.cs.biu.ac.il/~tsaban/Pdf/LaTeXCommonErrs.pdf %% for general tips \usepackage{listings} \usepackage{subfigure} \usepackage{bm} \usepackage{amsfonts} %% - also included by amssymb \usepackage{mathpazo} %% - because the OP uses mathpazo, optional %\usepackage{tufte-latex} \usepackage{comment} \usepackage{mathtools} \usepackage{bussproofs} \usepackage{hyperref} %\usepackage{cleveref} \)
\( %% Your math definitions here % \newcommand{\alphaequiv}{{\underset{\raise 0.7em\alpha}{=}}} \newcommand{\yields}{\Rightarrow} \newcommand{\derives}{\overset{*}{\yields}} \newcommand{\alphaequiv}{=_{\alpha}} \newcommand{\tto}[2]{{\overset{#1}{\underset{#2}{\longrightarrow}}}} \newcommand{\transitsto}[2]{{\overset{#1}{\underset{#2}{\longrightarrow}}}} \newcommand{\xtransitsto}[2]{{\underset{#2}{\xrightarrow{#1}}}} \newcommand{\xtransitsfrom}[2]{{\underset{#2}{\xleftarrow{#1}}}} \newcommand{\xto}[2]{{\xtransitsto{#1}{#2}}} \newcommand{\xfrom}[2]{{\xtransitsfrom{#1}{#2}}} \newcommand{\xreaches}[2]{{\underset{#2}{\xtwoheadrightarrow{#1}}}} \newcommand{\reaches}[2]{{\underset{#2}{\xtwoheadrightarrow{#1}}}} %\newcommand{\reaches}[2]{{\overset{#1}{\underset{#2}{\twoheadrightarrow}}}} %\newcommand{\goesto}[2]{\transitsto{#1}{#2}} %\newcommand{\betareducesto}{{\underset{\beta}{\rightarrow}}} \newcommand{\betareducesto}{\rightarrow_{\beta}} %\newcommand{\etareducesto}{{\underset{\eta}{\rightarrow}}} \newcommand{\etareducesto}{\rightarrow_{\eta}} %\newcommand{\betaetareducesto}{{\underset{\beta\ \eta}{\rightarrow}}} \newcommand{\betaetareducesto}{\rightarrow_{\beta\eta}} \newcommand{\preducesto}{\rhd} \newcommand{\psimplifiesto}{\stackrel{\scriptstyle{*}}{\rhd}} \newcommand{\lreducesto}{\rightsquigarrow} \newcommand{\lsimplifiesto}{\stackrel{\scriptstyle{*}}{\lreducesto}} \newcommand{\rewritesto}{\hookrightarrow} \newcommand{\goesto}[1]{\stackrel{#1}{\rightarrow}} \newcommand{\xgoesto}[1]{\xrightarrow{#1}} \newcommand{\reducesto}{\stackrel{}{\rightarrow}} \newcommand{\simplifiesto}{\stackrel{\scriptstyle{*}}{\rightarrow}} \newcommand{\connected}[1]{\stackrel{#1}{\leftrightarrow}} \newcommand{\joins}{\downarrow} \newcommand{\evaluatesto}{\Longrightarrow} %\newcommand{\lit}[1]{\hbox{\sf{#1}}} \newcommand{\lit}[1]{{\sf{#1}}} \newcommand{\true}{\lit{true}} \newcommand{\false}{\lit{false}} \def\Z{\mbox{${\mathbb Z}$}} \def\N{\mbox{${\mathbb N}$}} \def\P{\mbox{${\mathbb P}$}} \def\R{\mbox{${\mathbb R}$}} \def\T{\mbox{${\mathbb T}$}} \newcommand{\Rp}{{\mathbb{R}}^+} \def\Bool{\mbox{${\mathbb B}$}} \def\Q{\mbox{${\mathbb Q}$}} \def\sA{\mbox{${\cal A}$}} \def\sB{\mbox{${\cal B}$}} \def\sC{\mbox{${\cal C}$}} \def\sD{\mbox{${\cal D}$}} \def\sF{\mbox{${\cal F}$}} \def\sG{\mbox{${\cal G}$}} \def\sL{\mbox{${\cal L}$}} \def\sP{\mbox{${\cal P}$}} \def\sM{\mbox{${\cal M}$}} \def\sN{\mbox{${\cal N}$}} \def\sR{\mbox{${\cal R}$}} \def\sS{\mbox{${\cal S}$}} \def\sO{\mbox{${\cal O}$}} \def\sT{\mbox{${\cal T}$}} \def\sU{\mbox{${\cal U}$}} \def\th{\mbox{$\widetilde{h}$}} \def\tg{\mbox{$\widetilde{g}$}} \def\tP{\mbox{$\widetilde{P}$}} \def\norm{\mbox{$\parallel$}} \def\osum{${{\bigcirc}}\!\!\!\!{\rm s}~$} \def\pf{\noindent {\bf Proof}~~} \def\exec{\mathit{exec}} \def\Act{\mathit{A\!ct}} \def\Traces{\mathit{Traces}} \def\Spec{\mathit{Spec}} \def\uns{\mathit{unless}} \def\ens{\mathit{ensures}} \def\lto{\mathit{leads\!\!-\!\!to}} \def\a{\alpha} \def\b{\beta} \def\c{\gamma} \def\d{\delta} \def\sP{\mbox{${\cal P}$}} \def\sM{\mbox{${\cal M}$}} \def\sA{\mbox{${\cal A}$}} \def\sB{\mbox{${\cal B}$}} \def\sC{\mbox{${\cal C}$}} \def\sI{\mbox{${\cal I}$}} \def\sS{\mbox{${\cal S}$}} \def\sD{\mbox{${\cal D}$}} \def\sF{\mbox{${\cal F}$}} \def\sG{\mbox{${\cal G}$}} \def\sR{\mbox{${\cal R}$}} \def\tg{\mbox{$\widetilde{g}$}} \def\ta{\mbox{$\widetilde{a}$}} \def\tb{\mbox{$\widetilde{b}$}} \def\tc{\mbox{$\widetilde{c}$}} \def\tx{\mbox{$\widetilde{x}$}} \def\ty{\mbox{$\widetilde{y}$}} \def\tz{\mbox{$\widetilde{z}$}} \def\tI{\mbox{$\widetilde{I}$}} \def\norm{\mbox{$\parallel$}} \def\sL{\mbox{${\cal L}$}} \def\sM{\mbox{${\cal M}$}} \def\sN{\mbox{${\cal N}$}} \def\th{\mbox{$\widetilde{h}$}} \def\tg{\mbox{$\widetilde{g}$}} \def\tP{\mbox{$\widetilde{P}$}} \def\norm{\mbox{$\parallel$}} \def\to{\rightarrow} \def\ov{\overline} \def\gets{\leftarrow} \def\too{\longrightarrow} \def\To{\Rightarrow} %\def\points{\mapsto} %\def\yields{\mapsto^{*}} \def\un{\underline} \def\vep{$\varepsilon$} \def\ep{$\epsilon$} \def\tri{$\bigtriangleup$} \def\Fi{$F^{\infty}$} \def\Di{\Delta^{\infty}} \def\ebox\Box \def\emp{\emptyset} \def\leadsto{\rightharpoondown^{*}} \newcommand{\benum}{\begin{enumerate}} \newcommand{\eenum}{\end{enumerate}} \newcommand{\bdes}{\begin{description}} \newcommand{\edes}{\end{description}} \newcommand{\bt}{\begin{theorem}} \newcommand{\et}{\end{theorem}} \newcommand{\bl}{\begin{lemma}} \newcommand{\el}{\end{lemma}} % \newcommand{\bp}{\begin{prop}} % \newcommand{\ep}{\end{prop}} \newcommand{\bd}{\begin{defn}} \newcommand{\ed}{\end{defn}} \newcommand{\brem}{\begin{remark}} \newcommand{\erem}{\end{remark}} \newcommand{\bxr}{\begin{exercise}} \newcommand{\exr}{\end{exercise}} \newcommand{\bxm}{\begin{example}} \newcommand{\exm}{\end{example}} \newcommand{\beqa}{\begin{eqnarray*}} \newcommand{\eeqa}{\end{eqnarray*}} \newcommand{\bc}{\begin{center}} \newcommand{\ec}{\end{center}} \newcommand{\bcent}{\begin{center}} \newcommand{\ecent}{\end{center}} \newcommand{\la}{\langle} \newcommand{\ra}{\rangle} \newcommand{\bcor}{\begin{corollary}} \newcommand{\ecor}{\end{corollary}} \newcommand{\bds}{\begin{defns}} \newcommand{\eds}{\end{defns}} \newcommand{\brems}{\begin{remarks}} \newcommand{\erems}{\end{remarks}} \newcommand{\bxrs}{\begin{exercises}} \newcommand{\exrs}{\end{exercises}} \newcommand{\bxms}{\begin{examples}} \newcommand{\exms}{\end{examples}} \newcommand{\bfig}{\begin{figure}} \newcommand{\efig}{\end{figure}} \newcommand{\set}[1]{\{#1\}} \newcommand{\pair}[1]{\langle #1\rangle} \newcommand{\tuple}[1]{\langle #1\rangle} \newcommand{\size}[1]{| #1 |} \newcommand{\union}{\cup} \newcommand{\Union}{\bigcup} \newcommand{\intersection}{\cap} \newcommand{\Intersection}{\bigcap} \newcommand{\B}{\textbf{B}} %\newcommand{\be}[2]{\begin{equation} \label{#1} \tag{#2} \end{equation}} \newcommand{\abs}[1]{{\lvert}#1{\rvert}} \newcommand{\id}[1]{\mathit{#1}} \newcommand{\pfun}{\rightharpoonup} %\newcommand{\ra}[1]{\kern-1.5ex\xrightarrow{\ \ #1\ \ }\phantom{}\kern-1.5ex} %\newcommand{\ras}[1]{\kern-1.5ex\xrightarrow{\ \ \smash{#1}\ \ }\phantom{}\kern-1.5ex} \newcommand{\da}[1]{\bigg\downarrow\raise.5ex\rlap{\scriptstyle#1}} \newcommand{\ua}[1]{\bigg\uparrow\raise.5ex\rlap{\scriptstyle#1}} % \newcommand{\lift}[1]{#1_{\bot}} \newcommand{\signal}[1]{\tilde{#1}} \newcommand{\ida}{\stackrel{{\sf def}}{=}} \newcommand{\eqn}{\doteq} \newcommand{\deduce}[1]{\sststile{#1}{}} %% These don't sit very well with MathJax %% so we don't plan to use theorem like environments %% in org documents. %% instead we plan to use headings with %% 1. property drawers with a CLASS property identifying %% the environment %% 2. A tag with the same name as the CLASS property %% In LaTeX export, these turn into (sub)sections. %% See http://u.cs.biu.ac.il/~tsaban/Pdf/LaTeXCommonErrs.pdf %% \newtheorem{prop}[thm]{Proposition} %% \theoremstyle{plain}%default %% \newtheorem{theorem}{Theorem}[section] %% \newtheorem{lemma}{Lemma}[section] %% \newtheorem{corollary}{Corollary}[section] %% \newtheorem{definition}{Definition}[section] %% \newtheorem{remark}{Remark}[section] %% \newtheorem{example}{Example}[section] %% \newtheorem{exercise}{Exercise}[section] \newcommand{\less}[1]{#1_{<}} \newcommand{\pfn}{\rightharpoonup} \newcommand{\ffn}{\stackrel{{\sf fin}}{\rightharpoonup}} \newcommand{\stkout}[1]{\ifmmode\text{\sout{\ensuremath{#1}}}\else\sout{#1}\fi} % Caution: Not supported by MathJax! % ---------------------------------- % \DeclareMathSymbol{\shortminus}{\mathbin}{AMSa}{"39} % \usepackage{amsfonts} %% <- also included by amssymb % \DeclareMathSymbol{\shortminus}{\mathbin}{AMSa}{"39} \usepackage{mathpazo} %% <- because the OP uses mathpazo, optional \newcommand{\mbf}[1]{\mathbf{#1}} \newcommand{\floor}[1]{\left\lfloor #1 \right\rfloor} \newcommand{\ceil}[1]{\left\lceil #1 \right\rceil} \newcommand{\rel}{\twoheadrightarrow} \newcommand{\map}{\rightarrow} %\newcommand{\fixed}{\boldsymbol{\circlearrowleft}} \newcommand{\terminal}{\not\xto{}{}} \newcommand{\fixed}{\bm\circlearrowleft} \newcommand{\imp}{\rightarrow} \newcommand{\dimp}{\leftrightarrow} % double implication \newcommand{\lequiv}{\Longleftrightarrow} % logical equivalence \newcommand{\limplies}{\Rightarrow} \newcommand{\lxor}{\veebar} \)
UP | HOME

Discrete Dynamical Systems and the mapcode approach to Algorithmic Problem Solving

Table of Contents

1 Introduction:

We study discrete dynamical systems, which are then used as a framework for algorithmic problem solving. Much of this material is from Chapters 1-2, "An introduction to Mathematical Computer Science, K Viswanath. Orient Blackswan, India 2008."

1.1 Discrete Dynamical System

A discrete dynamical system, also called a discrete flow, or a discrete process, is a tuple \(\pair{X,F}\) where \(X\) is a set called the state space and \(F\) is a function from \(X\) to \(X\), called the program map.

Here are simple examples of a dynamical system:

  • \(\pair{\N,\id{incr}}\), where \(\id{incr}(x) = x+1\).
  • \(\pair{\set{t, f},\id{inv}}\), where \(\id{inv}(x) = \set{t\mapsto\ f, f\mapsto\ t}\).
  • \(\pair{\Z, \id{dim}}\) where
\begin{align*} \id{dim}(x) & = x, & \mbox{if $x = 0$}\\ & = x-1, & \mbox{if $x > 0$}\\ & = x+1, & \mbox{if $x < 0$} \end{align*}

1.2 Trajectory

Let \(x\in X\). The trajectory of \(x\) wrt to the dynamical system \(\pair{X,F}\), written \(\id{tr}(x)\) is the infinite sequence

\[ \id{tr}(x) = [x, F(x), F(F(x)), F^{3}(x), \ldots]\]

1.3 Examples

  • Consider \(\pair{\N, \id{incr}}\). Then

\[\id{tr}(4) = [4, 5, 6, \ldots]\]

  • Consider \(\pair{\Bool, \id{inv}}\). Then

    \[ \id{tr}(t) = [t, f, t, \ldots]\]

  • Consider \(\pair{\Z, \id{dim}}\). Then

\[ \id{tr}(4) = [4, 3, 2, 1, 0, 0, 0, \ldots]\]

\[ \id{tr}(-4) = [-4, -3, -2, -1, 0, 0, 0, \ldots]\]

\[ \id{tr}(0) = [0, 0, 0, \ldots]\]

1.4 Reachability

Let \(x,y\in X\). We say \(y\) is reachable from \(x\), if \(y=F^{n}(x)\) for some \(n\in N\). We also say that \(x\) reaches \(y\).

If \(x\) is an element of \(X\) and \(Y\) is a subset of \(X\), then we say that \(x\) reaches \(Y\) if \(x\) reaches some element of \(Y\).

1.5 Fixed point

Let \(F:X\rightarrow X\). An element \(x\in X\) is a fixed point of \(F\) if \(F(x) = x\). Let \(\id{fix}(F)\) denote the subset of \(X\) containing all fixed points of \(F\). Note that a function \(F\) may have 0, finite, or infinite number of fixed points.

1.6 Invariant sets

A subset \(A\) of \(X\) is an invariant set for \(F\) if for all \(x\in X\): \(x\in A\) implies \(F(x)\in A\). Another way of saying this is that \(F(A)\subseteq A\).

1.6.1 Examples

Consider the following system \(\pair{\N, x\mapsto x+2}\). Then both the subsets \(\id{evens} = \set{0, 2, 4, 6, \ldots}\) and \(\id{odds} = \set{1, 3, 5, 7, \ldots}\) are invariants for \(F\).

1.7 Convergent set

\(\id{con}(F)\) denotes the set of all elements \(x\) such that \(x\) reaches \(\id{fix}(F)\). We say that \(x\) is converges or terminates for \(F\) if \(x\in \id{con}(F)\).

1.8 Final state

Let \(x\) converge for \(F\). Let \(n\) be the smallest natural such that \(F^{n}(x)\) is a fixed point. Then, \(n\) is called the runtime of the computation starting with \(x\). \(F^n(x)\) is called the final state of the initial state \(x\).

1.9 Limit map

The function \(F^{\infty}:\id{con}(F)\rightarrow \id{fix}(F)\) is called the limit map of \(F\). If \(x\in \id{con}(F)\), we say that \(x\) terminates at \(F^\infty(x)\).

2 Algorithmic Problem Solving

Computers are useful for solving problems. That said, however, algorithmic problem solving requires that we first identify the problem precisely. Second, we mention the primitive operations that may be used by the algorithm to solve the problem.

A problem specification consists of

  • An input space \(A\)
  • An output space \(B\)
  • A function \(f:A\rightarrow B\)

Note that this is the function for which we need to design an algorithm. We know the function, but not an algorithm that computes it.

2.1 Example: The factorial problem

Consider the factorial function \(!:\N\rightarrow \N\). Here the input and output spaces are both \(\N\). We are required to compute the factorial of a number using the following primitive operations:

  • decrement operator on natural numbers \(n\mapsto n-1\)
  • multiplication operator on naturals
  • comparison with the natural number 0

2.2 The mapcode approach to problem solving

2.2.1 Problem

The mapcode approach to algorithmic problem solving starts with identifying a problem specification. This includes an input space \(A\), an output space \(B\) and a function \(f\) from the input to the output space.

2.2.2 Solution

The next step is to construct a solution. The solution is in two parts. The first consists of defining three components:

A discrete dynamical system \(D=\pair{X,F}\)
The state space \(X\) of \(D\) may be thought of the input space \(A\) augmented with more variables.
An input map \(\rho:A\rightarrow X\)
\(\rho\) maps the input space of the problem to the state space of \(D\).
An output map \(\pi:X\rightarrow B\)
\(\pi\) maps the state space of \(D\) to the output space of the problem.

2.2.3 Correctness

The second part of the solution requires proving that the trip \(\pair{\rho, D, \pi}\) solve the problem \(f\). This requires verifying the following properties.

  • 0. \(\rho\), \(F\) and \(\pi\) use only the primitive operators.
  • 1. \(\id{fix}(F)\) is non-empty.
  • 2. \(\id{con}(F)\) is non-empty.
  • 3. \(\id{codomain}(\rho) \subseteq \id{con}(F)\). (Termination)
  • 4. \(\rho;F^\infty;\pi = f\) (Commute property)

The idea is that given an element \(a\) from \(A\), \(\rho\) maps \(a\) to \(\id{con}(F)\). This means that \(x=\rho(a)\) reaches a fixed point, say \(x^\infty=F^\infty(x)\). Then \(\pi\) maps \(x^\infty\) to an element in \(B\). The result of this should be equivalent to computing \(f\). That is, we expect, \(\rho; F^\infty; \pi = f\).

2.2.4 Commutative Diagram

The following commutative diagram summarizes the commute property \(\rho;F^\infty;\pi=f\).

\begin{array}{c} A & \ra{f} & B\\ \da{\rho} & & \ua{\pi} \\ X & \ra{F^\infty} & X \end{array}

2.2.5 Invariant

The process of establishing the commutativity step usually requires designing an invariant. The invariant is true for the trajectory starting with \(\rho(a)\).

2.3 Mapcode framework to algorithmically solve the factorial problem

Problem specification
  • Input space is \(A=\N\).
  • Output space is \(B=\N\).
  • The function to be computed is \(!:\N\rightarrow \N\), the factorial function.
Solution
  • Discrete Dynamical system \(D=\pair{X,F}\) where

    • State space \(X\) is \(\N\times \N\).
    • Program map is \(F:X\rightarrow X\) is defined as
    \begin{align*} F(0,a) &= (0,a)\\ F(i, a) &= (i-1, a*i) \qquad i>0 \end{align*}
  • \(\rho: A\rightarrow X\) defined where \(\rho(n) = (n, 1)\).
  • \(\pi: X\rightarrow B\) where \(\pi(i,a) = a\).

2.3.1 Sample Trajectories

\begin{align*} \id{tr}(2, 3) &= [(2, 3), (1, 6), (0, 6), (0, 6), \ldots]\\ \id{tr}(4, 2) &= [(4, 2), (3, 8), (2, 24), (1, 48), (0, 48), (0, 48), \ldots]\\ \id{tr}(3, 1) &= [(3, 1), (2, 3), (1, 6), (0, 6), (0, 6), \ldots]\\ \id{tr}(0, 1) &= [(0, 1), (0, 1), \ldots] \end{align*}

2.3.2 Proof of Correctness

\(\rho\), \(F\) and \(\pi\) use only the primitive operators
This is true by inspecting the definitions of each of these functions.
\(\id{fix}(F)\) is non-empty
Note that every fixed point of \(F\) is of the form \((0, a)\) for \(a\in \N\). In other words, \(\id{fix}(F)= \set{0}\times \N\), which is non-empty.
\(\id{con}(F)\) is non-empty
Note that every initial state \((i,a)\) reaches a final state \((i, a^\infty)\) after exactly \(i\) steps. Hence \(\id{con}(F) = \N\times \N\), the entire state space, which is non-empty.
\(\id{codomain}(\rho) \subseteq \id{con}(F)\) (Termination)
Note that \(\id{con}(F) = X\), so this is trivially true. This implies termination, since an input \(n\in A\) is mapped to an element \((n,1)\) which converges after \(i\) steps.
Invariant
Given \(n\in \N\), let \(P(n)= \set{(i,a)\ |\ a*i! = n!}\). We show that \(P(n)\) is an invariant for \(F\). Assume \((i,a)\in P(n)\). We need to show that \(F(i,a)\in P(n)\). Now, \(F(i,a)=(i-1, a*i)\). Clearly, \((a*i)*(i-1)! = a*i! = n!\). The second equality is due to the assumption that \((i,a)\in P(n)\). Therefore \(F(i,a)\in P(n)\).
\(\rho ; F^{\infty}; \pi = f\) (Commute Property)
Let \(n\in A\). Then \(\rho(n) = (n, 1)\). Clearly, \((n,1)\in P(n)\). By induction on \(k\), \(F^{k}(n,1) \in P\). We know that \((n,1)\) terminates at \((0, a)\) for some \(a\) after \(n\) steps. Since \((0,a)\in P(n)\), it means that \(a*0! = n!\). From this, it follows that \(a = n!\). Since \(\pi(0,a)=a\), this just proves that \((\rho; F^{\infty};\pi)(n) = n!\).

3 Implementing the mapcode combinator

;;; fixed-point? : [F:[X -> X], x:X] -> boolean?
(define fixed-point?
  (lambda (F x)
    (equal? (F x) x)))


;;; mapcode : [init:[A -> X], F:[X -> X], done:[X -> B]] -> B
(define mapcode
  (lambda (init F done) ;; \rho, F, \pi
    (lambda (a)
      (letrec ([loop
		(lambda (x)
		  (if (fixed-point? F x)
		      (done x)
		      (loop (F x))))])
	(loop (init a))))))

4 Factorial using mapcode

5 Factorial using mapcode

Here is factorial using mapcode

;;; !: nat? -> nat?
(define !
  (mapcode
   ;; init
   (lambda (n)
     (list n 1))
   ;; next
   (lambda (x)
     (match x
       [(list 0 a) x]
       [(list i a) (list (sub1 i) (* a i))]))
   ;; done
   second))

;;; test cases
(check-equal? (! 0) 1 "!0")
(check-equal? (! 2) 2 "!2")
(check-equal? (! 3) 6 "!3")

6 Tangle   noexport

#lang racket
(provide (all-defined-out))
(require racket/list)
(require racket/match)
(require rackunit)
(require rackunit/text-ui)
(require "mapcode.rkt")
;;; !: nat? -> nat?
(define !
  (mapcode
   ;; init
   (lambda (n)
     (list n 1))
   ;; next
   (lambda (x)
     (match x
       [(list 0 a) x]
       [(list i a) (list (sub1 i) (* a i))]))
   ;; done
   second))

;;; test cases
(check-equal? (! 0) 1 "!0")
(check-equal? (! 2) 2 "!2")
(check-equal? (! 3) 6 "!3")

Author: choppell

Created: 2023-11-03 Fri 16:47

Validate