# ------------------------
# Universal Turing machine
# ------------------------
#
# See https://en.wikipedia.org/wiki/Universal_Turing_machine

@prefix log: <http://www.w3.org/2000/10/swap/log#>.
@prefix list: <http://www.w3.org/2000/10/swap/list#>.
@prefix : <urn:example:>.

# declare components
:compute a log:Component.
:find a log:Component.
:continue a log:Component.
:move a log:Component.
:reverse a log:Component.

# interpreter for Univeral Turing Machine
(_:OutTape _:Machine _:I) log:onNegativeSurface {
    () log:onNegativeSurface {
        () :compute _:OutTape.
    }.
    _:Machine :start _:I.
    (_:I () "#" ()) :find _:OutTape.
}.

(_:List _:OutTape _:Head _:Tail _:Machine _:I) log:onNegativeSurface {
    () log:onNegativeSurface {
        _:List :compute _:OutTape.
    }.
    _:List list:firstRest (_:Head _:Tail).
    _:Machine :start _:I.
    (_:I () _:Head _:Tail) :find _:OutTape.
}.

(_:State _:Left _:Cell _:Right _:OutTape _:Write _:Move _:Next _:A _:B _:C) log:onNegativeSurface {
    () log:onNegativeSurface {
        (_:State _:Left _:Cell _:Right) :find _:OutTape.
    }.
    (_:State _:Cell _:Write _:Move) :tape _:Next.
    (_:Move _:Left _:Write _:Right _:A _:B _:C) :move true.
    (_:Next _:A _:B _:C) :continue _:OutTape.
}.

(_:Left _:Cell _:Right _:OutTape _:R _:List) log:onNegativeSurface {
    () log:onNegativeSurface {
        (:halt _:Left _:Cell _:Right) :continue _:OutTape.
    }.
    _:Left :reverse _:R.
    _:List list:firstRest (_:Cell _:Right).
    (_:R _:List) list:append _:OutTape.
}.

(_:State _:Left _:Cell _:Right _:OutTape) log:onNegativeSurface {
    () log:onNegativeSurface {
        (_:State _:Left _:Cell _:Right) :continue _:OutTape.
    }.
    (_:State _:Left _:Cell _:Right) :find _:OutTape.
}.

(_:Cell _:Right _:L) log:onNegativeSurface {
    () log:onNegativeSurface {
        (:left () _:Cell _:Right () "#" _:L) :move true.
    }.
    _:L list:firstRest (_:Cell _:Right).
}.

(_:List _:Cell _:Right _:Tail _:Head _:L) log:onNegativeSurface {
    () log:onNegativeSurface {
        (:left _:List _:Cell _:Right _:Tail _:Head _:L) :move true.
    }.
    _:List list:firstRest (_:Head _:Tail).
    _:L list:firstRest (_:Cell _:Right).
}.

(_:Left _:Cell _:Right) log:onNegativeSurface {
    () log:onNegativeSurface {
        (:stop _:Left _:Cell _:Right _:Left _:Cell _:Right) :move true.
    }.
}.

(_:Left _:Cell _:L) log:onNegativeSurface {
    () log:onNegativeSurface {
        (:right _:Left _:Cell () _:L "#" ()) :move true.
    }.
    _:L list:firstRest (_:Cell _:Left).
}.

(_:Left _:Cell _:List _:L _:Head _:Tail) log:onNegativeSurface {
    () log:onNegativeSurface {
        (:right _:Left _:Cell _:List _:L _:Head _:Tail) :move true.
    }.
    _:List list:firstRest (_:Head _:Tail).
    _:L list:firstRest (_:Cell _:Left).
}.

() log:onNegativeSurface {
    () log:onNegativeSurface {
        () :reverse ().
    }.
}.

(_:List _:Reverse _:Head _:Tail _:R) log:onNegativeSurface {
    () log:onNegativeSurface {
        _:List :reverse _:Reverse.
    }.
    _:List list:firstRest (_:Head _:Tail).
    _:Tail :reverse _:R.
    (_:R (_:Head)) list:append _:Reverse.
}.

# a Turing machine to add 1 to a binary number
:add1 :start 0.

(0 0 0 :right) :tape 0.
(0 1 1 :right) :tape 0.
(0 "#" "#" :left) :tape 1.
(1 0 1 :stop) :tape :halt.
(1 1 0 :left) :tape 1.
(1 "#" 1 :stop) :tape :halt.

# query
(_:A1 _:A2 _:A3 _:A4) log:onNegativeSurface {
    (1 0 1 0 0 1) :compute _:A1.
    (1 0 1 1 1 1) :compute _:A2.
    (1 1 1 1 1 1) :compute _:A3.
    () :compute _:A4.
    () log:onNegativeAnswerSurface {
        (1 0 1 0 0 1) :compute _:A1.
        (1 0 1 1 1 1) :compute _:A2.
        (1 1 1 1 1 1) :compute _:A3.
        () :compute _:A4.
    }.
}.
