use crate::{
bool::{Bool, False},
list::bool::{BoolList, Cons, Nil},
nat::{Nat, Succ, Zero},
types::assert_same_type,
uninhabited::PhantomUninhabited,
};
pub struct Tape<Left: BoolList, Head: Bool, Right: BoolList>(
PhantomUninhabited<(Left, Head, Right)>,
);
pub trait TapeT: private::Sealed {
type Left: BoolList;
type Head: Bool;
type Right: BoolList;
}
impl<Left: BoolList, Head: Bool, Right: BoolList> TapeT for Tape<Left, Head, Right> {
type Left = Left;
type Head = Head;
type Right = Right;
}
mod private {
use super::*;
pub trait Sealed {}
impl<Left: BoolList, Head: Bool, Right: BoolList> Sealed for Tape<Left, Head, Right> {}
}
pub type BlankTape = Tape<Nil, False, Nil>;
pub type WriteAndLeft<Left, Right, Write> =
Tape<<Left as BoolList>::Tail, <Left as BoolList>::Head, Cons<Write, Right>>;
pub type WriteAndRight<Left, Right, Write> =
Tape<Cons<Write, Left>, <Right as BoolList>::Head, <Right as BoolList>::Tail>;
pub trait TuringMachine {}
pub trait State {}
pub enum Halt {}
impl State for Halt {}
pub trait Configuration {
type Tape: TapeT;
type State: State;
}
pub trait Step<TM: TuringMachine> {
type Next: Configuration;
}
pub trait Run<TM: TuringMachine> {
type FinalTape: TapeT;
type Steps: Nat;
}
pub struct HaltConfiguration<Left: BoolList, Head: Bool, Right: BoolList>(
PhantomUninhabited<(Left, Head, Right)>,
);
impl<Left: BoolList, Head: Bool, Right: BoolList> Configuration
for HaltConfiguration<Left, Head, Right>
{
type Tape = Tape<Left, Head, Right>;
type State = Halt;
}
impl<TM: TuringMachine, Left: BoolList, Head: Bool, Right: BoolList> Run<TM>
for HaltConfiguration<Left, Head, Right>
{
type FinalTape = <Self as Configuration>::Tape;
type Steps = Zero;
}
pub trait NonHaltState: State {}
pub struct NonHaltConfiguration<Left: BoolList, Head: Bool, Right: BoolList, State: NonHaltState>(
PhantomUninhabited<(Left, Head, Right, State)>,
);
impl<Left: BoolList, Head: Bool, Right: BoolList, State: NonHaltState> Configuration
for NonHaltConfiguration<Left, Head, Right, State>
{
type Tape = Tape<Left, Head, Right>;
type State = State;
}
impl<TM: TuringMachine, Left: BoolList, Head: Bool, Right: BoolList, State: NonHaltState> Run<TM>
for NonHaltConfiguration<Left, Head, Right, State>
where
Self: Step<TM>,
<Self as Step<TM>>::Next: Run<TM>,
{
type FinalTape = <<Self as Step<TM>>::Next as Run<TM>>::FinalTape;
type Steps = Succ<<<Self as Step<TM>>::Next as Run<TM>>::Steps>;
}
pub type RunOn<State, Tape> = NonHaltConfiguration<
<Tape as TapeT>::Left,
<Tape as TapeT>::Head,
<Tape as TapeT>::Right,
State,
>;
pub type RunOnBlank<State> = RunOn<State, BlankTape>;
pub type HaltStep<Tape> =
HaltConfiguration<<Tape as TapeT>::Left, <Tape as TapeT>::Head, <Tape as TapeT>::Right>;
pub type NonHaltStep<Tape, State> = NonHaltConfiguration<
<Tape as TapeT>::Left,
<Tape as TapeT>::Head,
<Tape as TapeT>::Right,
State,
>;
pub trait StepN<N: Nat, TM: TuringMachine> {
type Configuration: Configuration;
}
impl<N: Nat, TM: TuringMachine, Left: BoolList, Head: Bool, Right: BoolList> StepN<N, TM>
for HaltConfiguration<Left, Head, Right>
{
type Configuration = Self;
}
impl<TM: TuringMachine, Left: BoolList, Head: Bool, Right: BoolList, State: NonHaltState>
StepN<Zero, TM> for NonHaltConfiguration<Left, Head, Right, State>
{
type Configuration = Self;
}
impl<
N: Nat,
TM: TuringMachine,
Left: BoolList,
Head: Bool,
Right: BoolList,
State: NonHaltState,
> StepN<Succ<N>, TM> for NonHaltConfiguration<Left, Head, Right, State>
where
Self: Step<TM>,
<Self as Step<TM>>::Next: StepN<N, TM>,
{
type Configuration = <<Self as Step<TM>>::Next as StepN<N, TM>>::Configuration;
}
mod macros {
#[macro_export]
macro_rules! state {
($name:ident) => {
enum $name {}
impl $crate::turing_machine::State for $name {}
impl $crate::turing_machine::NonHaltState for $name {}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __transition_aux {
($tm:ty: ($head:ty, $state:ty) => $next:tt) => {
impl<Left: $crate::list::bool::BoolList, Right: $crate::list::bool::BoolList>
$crate::turing_machine::Step<$tm>
for $crate::turing_machine::NonHaltConfiguration<Left, $head, Right, $state>
{
#[allow(unused_parens)]
type Next = $next;
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __transition_non_halt_aux {
($tm:ty: ($head:ty, $state:ty) => ($write:ty, $move:ident, $new_state:ty)) => {
$crate::__transition_aux!($tm: ($head, $state) =>
($crate::turing_machine::NonHaltStep<
$crate::turing_machine::$move<Left, Right, $write>,
$new_state,
>));
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __transition_halt_aux {
($tm:ty: ($head:ty, $state:ty) => ($write:ty, $move:ident)) => {
$crate::__transition_aux!($tm: ($head, $state) =>
($crate::turing_machine::HaltStep<
$crate::turing_machine::$move<Left, Right, $write>,
>));
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __to_bool {
(0) => {
$crate::bool::False
};
(1) => {
$crate::bool::True
};
}
#[macro_export]
macro_rules! transition {
($tm:ty: ($head:tt, $state:ty) => ($write:tt, R, Z)) => {
$crate::__transition_halt_aux!($tm: ($crate::__to_bool!($head), $state) => ($crate::__to_bool!($write), WriteAndRight));
};
($tm:ty: ($head:tt, $state:ty) => ($write:tt, L, Z)) => {
$crate::__transition_halt_aux!($tm: ($crate::__to_bool!($head), $state) => ($crate::__to_bool!($write), WriteAndLeft));
};
($tm:ty: ($head:tt, $state:ty) => ($write:tt, R, $new_state:ty)) => {
$crate::__transition_non_halt_aux!($tm: ($crate::__to_bool!($head), $state) => ($crate::__to_bool!($write), WriteAndRight, $new_state));
};
($tm:ty: ($head:tt, $state:ty) => ($write:tt, L, $new_state:ty)) => {
$crate::__transition_non_halt_aux!($tm: ($crate::__to_bool!($head), $state) => ($crate::__to_bool!($write), WriteAndLeft, $new_state));
};
}
#[macro_export]
macro_rules! turing_machine {
($tm:ident; [];) => {
enum $tm {}
impl $crate::turing_machine::TuringMachine for $tm {}
};
($tm:ident; []; $from:tt => $to:tt; $($froms:tt => $tos:tt;)*) => {
$crate::transition!($tm: $from => $to);
$crate::turing_machine! {
$tm;
[];
$($froms => $tos;)*
}
};
($tm:ident; [$state:ident $($states:ident)*]; $($froms:tt => $tos:tt;)*) => {
$crate::state!($state);
$crate::turing_machine! {
$tm;
[$($states)*];
$($froms => $tos;)*
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __tape_aux {
([] [$($left_rev:tt)*] $head:tt [$($right:tt)*]) => {
$crate::turing_machine::Tape<
$crate::to_bool_list!($($left_rev),*),
$crate::__to_bool!($head),
$crate::to_bool_list!($($right),*)
>
};
([$x:tt $($left:tt)*] [$($left_rev:tt)*] $head:tt [$($right:tt)*]) => {
$crate::__tape_aux!([$($left)*] [$x $($left_rev)*] $head [$($right)*])
};
}
#[macro_export]
macro_rules! tape {
([$($left:tt)*] $head:tt [$($right:tt)*]) => {
$crate::__tape_aux!([$($left)*] [] $head [$($right)*])
};
}
}
mod test {
use super::*;
use crate::{bool::True, nat, nat::consts::*, tape, turing_machine};
const _: () = assert_same_type::<tape!([] 0 []), Tape<Nil, False, Nil>>();
const _: () = assert_same_type::<tape!([] 1 []), Tape<Nil, True, Nil>>();
const _: () =
assert_same_type::<tape!([1 0] 0 []), Tape<Cons<False, Cons<True, Nil>>, False, Nil>>();
const _: () =
assert_same_type::<tape!([] 0 [0 1]), Tape<Nil, False, Cons<False, Cons<True, Nil>>>>();
mod one_state_busy_beaver {
use super::*;
turing_machine! {
TM;
[A];
(0, A) => (1, R, Z);
}
#[allow(dead_code)]
type Result = RunOnBlank<A>;
const _: () = assert_same_type::<<Result as Run<TM>>::FinalTape, tape!([1] 0 [])>();
const _: () = assert_same_type::<<Result as Run<TM>>::Steps, _1>();
}
mod two_state_busy_beaver {
use super::*;
turing_machine! {
TM;
[A B];
(0, A) => (1, R, B);
(1, A) => (1, L, B);
(0, B) => (1, L, A);
(1, B) => (1, R, Z);
}
#[allow(dead_code)]
type Result = RunOnBlank<A>;
const _: () = assert_same_type::<<Result as Run<TM>>::FinalTape, tape!([1 1] 1 [1])>();
const _: () = assert_same_type::<<Result as Run<TM>>::Steps, _6>();
}
mod three_state_busy_beaver {
use super::*;
turing_machine! {
TM;
[A B C];
(0, A) => (1, R, B);
(1, A) => (1, R, Z);
(0, B) => (0, R, C);
(1, B) => (1, R, B);
(0, C) => (1, L, C);
(1, C) => (1, L, A);
}
#[allow(dead_code)]
type Result = RunOnBlank<A>;
const _: () = assert_same_type::<<Result as Run<TM>>::FinalTape, tape!([1 1 1] 1 [1 1])>();
const _: () = assert_same_type::<<Result as Run<TM>>::Steps, _14>();
}
mod four_state_busy_beaver {
use super::*;
turing_machine! {
TM;
[A B C D];
(0, A) => (1, R, B);
(1, A) => (1, L, B);
(0, B) => (1, L, A);
(1, B) => (0, L, C);
(0, C) => (1, R, Z);
(1, C) => (1, L, D);
(0, D) => (1, R, D);
(1, D) => (0, R, A);
}
#[allow(dead_code)]
type Result = RunOnBlank<A>;
const _: () = assert_same_type::<
<Result as Run<TM>>::FinalTape,
tape!([1] 0 [1 1 1 1 1 1 1 1 1 1 1 1]),
>();
const _: () = assert_same_type::<<Result as Run<TM>>::Steps, nat!(1, 0, 7)>();
}
mod adder {
use super::*;
turing_machine! {
TM;
[A B C D];
(1, A) => (1, R, A);
(0, A) => (1, R, B);
(1, B) => (1, R, B);
(0, B) => (0, L, C);
(1, C) => (0, L, D);
(1, D) => (1, L, D);
(0, D) => (0, R, Z);
}
#[allow(dead_code)]
type Result = RunOn<A, tape!([] 1 [1 1 0 1 1])>;
const _: () =
assert_same_type::<<Result as Run<TM>>::FinalTape, tape!([0] 1 [1 1 1 1 0 0])>();
}
mod left_non_palindrome {
use super::*;
turing_machine! {
TM;
[A B];
(0, A) => (1, R, B);
(0, B) => (0, R, Z);
}
#[allow(dead_code)]
type Result = RunOnBlank<A>;
const _: () = assert_same_type::<<Result as Run<TM>>::FinalTape, tape!([1 0] 0 [])>();
}
mod step_n {
use super::*;
turing_machine! {
TM;
[A];
(0, A) => (1, R, A);
}
#[allow(dead_code)]
type Result = RunOnBlank<A>;
const _: () = assert_same_type::<
<<Result as StepN<_0, TM>>::Configuration as Configuration>::Tape,
tape!([] 0 []),
>();
const _: () = assert_same_type::<
<<Result as StepN<_1, TM>>::Configuration as Configuration>::Tape,
tape!([1] 0 []),
>();
const _: () = assert_same_type::<
<<Result as StepN<_2, TM>>::Configuration as Configuration>::Tape,
tape!([1 1] 0 []),
>();
const _: () = assert_same_type::<
<<Result as StepN<_10, TM>>::Configuration as Configuration>::Tape,
tape!([1 1 1 1 1 1 1 1 1 1] 0 []),
>();
}
}