P′′

(hereafter written P′′) is a primitive programming language created by Corrado Böhm 1,2 in 1964 to describe a family of Turing machines.

Syntax

 * 1) R and &lambda; are words in P&prime;&prime;.
 * 2) If p and q are words in P&prime;&prime;, then pq is a word in P&prime;&prime;.
 * 3) If q is a word in P&prime;&prime;, then (q) is a word in P&prime;&prime;.
 * 4) Only words derivable from the previous three rules are words in P&prime;&prime;.

In BNF:

Semantics

 * {a0, a1, ..., an}(n &ge; 1) is the tape-alphabet of a Turing machine with left-infinite tape, a0 being the blank symbol.
 * R</tt> means move the tape-head rightward one cell (if any).
 * &lambda;</tt> means replace the current symbol ai</tt> by ai+1</tt> (taking an+1 = a0</tt>), and then move the tape-head leftward one cell.
 * (q)</tt> means iterate q</tt> in a while-loop, with condition that the current symbol is not a0</tt>.
 * A program is a word in P&prime;&prime;. Execution of a program proceeds left-to-right, executing R</tt>, &lambda;</tt>, and (q)</tt> as they are encountered, until there is nothing more to execute.

Relation to other programming languages
Brainfuck (apart from its I/O instructions) is a simple informal variation of Böhm's P&prime;&prime;. Böhm1 gives explicit P&prime;&prime; programs for each of a set of basic functions sufficient to compute any partial recursive function -- and these programs are constructed entirely from six P&prime;&prime; words precisely equivalent to the respective Brainfuck commands,  ,  ,  ,  , and.

P&prime;&prime; was the first "goto-less" or "structured programming" language proved2 to be functionally equivalent to languages that use gotos.

Implementation
A Haskell implementation:

{-# LANGUAGE TypeOperators #-}

module P'' where

import Control.Category ((>>>)) import Control.Lens hiding (Tape) import Control.Monad

data Term = R | L | Seq Term Term | Loop Term type Tape = Top :>> [Int] :>> Int

-- Run a P'' term over a tape, in an alphabet of size n. -- Returns Nothing if the program moves off the tape. Note -- that directions are flipped; the left-infinite tape is -- implemented as a right-infinite list zipper. runTerm :: Int -> Term -> Tape -> Maybe Tape runTerm n R        = leftward runTerm n L        = focus %~ (\x -> succ x `mod` n) >>> rightward runTerm n (Seq p q) = runTerm n p >=> runTerm n q runTerm n (Loop p) = \tape -> case tape ^. focus of       0 -> Just tape _ -> runTerm n p >=> runTerm n (Loop p) $ tape

-- Run a P'' program over an empty tape. runP'' :: Int -> Term -> Maybe Tape runP'' n p = runTerm n p blankTape where blankTape = zipper (repeat 0) & fromWithin traverse

Example usage: define a program that calculates, then run it and print the first 10 tape elements.

prog :: Term prog = let s = foldr1 Seq in s [L, R, Loop $ s [L, L, R, R]]

main :: IO main = print $ runP'' 256 prog <&> rezip <&> take 10

External resources

 * P′′ at Wikipedia describes an explicit example program from Böhm.1