(* Micha�l P�RIN, Verimag / Universit� Grenoble-Alpes, F�vrier 2017 * * Part of the project TURING MACHINES FOR REAL * * Representation of a Band of a Turing Machine * * - Required modules: Pretty, Graphics -> Color -> Html -> Symbol -> Alphabet * * - Compilation: ocaml Pretty.cmo Graphics.cma Color.cmo Html.cmo Symbol.cmo Alphabet.cmo Band.ml *) open Symbol open Alphabet type band = { left: Symbol.t list ; head: Symbol.t ; right: Symbol.t list ; color: Color.t ; alphabet: Alphabet.t (* PROJECT 2017 * The alphabet is needed for translation into a binary representation of the symbols. * The alphabet is associated with the band (instead of being associated with the TM) for two reasons: * 1. outside the execution of a TM on the band, we would not know the alphabet and we would not be able to perform translation * 2. we will apply several TM in sequence on the band so they should agree and exchange the alphabet: complicated... * 3. Some of these TM can be generic, meaning that their instanciations depends on the alphabet * * Thus, it seems more convenient that the band sets the alphabet at creation. *) } module Band = (struct type t = band let (empty: band) = { left = [] ; head = B ; right = [] ; color = Color.COL "LightGray" ; alphabet = Alphabet.empty } let (make: Alphabet.t -> symbols -> band) = fun alphabet symbols -> match symbols with | [] -> { empty with alphabet = alphabet ; right = [] } | s::ymbols -> { empty with alphabet = alphabet ; head = s ; right = ymbols } let (nb_cells: band -> int * int) = fun band -> (List.length band.left, List.length band.right) (* /!\ The left part of the band is written in the reverse ordrer. It is easier to implement this way. A band containing a b c d (e) f g h with the head on (e) will be encoded by { left = [d;c;b;a] ; head = e ; right = [f;g;h] } *) let (move_head_right: band -> band) = fun band -> match band.right with | [] -> { band with left = band.head::band.left ; head = B ; right = [] } | s::ymbols -> { band with left = band.head::band.left ; head = s ; right = ymbols } let (move_head_left: band -> band) = fun band -> match band.left with | [] -> { band with left = [] ; head = B ; right = band.head::band.right } | s::lobmys -> { band with left = lobmys ; head = s ; right = band.head::band.right } let (write: symbol -> band -> band) = fun symbol band -> { band with head = symbol } let rec (zip_complete_with: 'op -> 'op list -> band list -> ('op * band) list) = fun nop operations bands -> match operations,bands with | [], [] -> [] | o::operations, b::bands -> (o,b) :: (zip_complete_with nop operations bands) | [], b::bands -> (nop,b) :: (zip_complete_with nop [] bands) | _, [] -> failwith "Band.zip: missing band" (* EQUIVALENCE *) let rec (remove_left_blanks: Symbol.t list -> Symbol.t list) = fun symbols -> match symbols with | [] -> [] | s::ymbols -> if s=B then remove_left_blanks ymbols (* BUG FIXED by Adrian Amaglio 05/04/2017 * else s::(remove_left_blanks ymbols) -- removes all blanks *) else symbols open Tricks let rec (remove_right_blanks: Symbol.t list -> Symbol.t list) = fun symbols -> symbols >> List.rev >> remove_left_blanks >> List.rev let (symbols_of: band -> Symbol.t list) = fun band -> let right = remove_right_blanks (band.head :: band.right) and left = remove_left_blanks (List.rev band.left) in left @ right let (equivalent: band -> band -> bool) = fun band1 band2 -> (symbols_of band1) = (symbols_of band2) (* PRETTY PRINTING *) (* ascii *) let (to_ascii: band -> string) = fun band -> let strings = List.map Symbol.to_ascii (List.rev band.left) @ [ Pretty.ascii_underline (Pretty.ascii_green (Symbol.to_ascii band.head)) ] @ List.map Symbol.to_ascii (band.right) in String.concat "." strings let (to_ascii_many: band list -> string) = fun bands -> String.concat "\n" (List.map to_ascii bands) (* html *) let (cell_to_html: band -> symbol -> Html.cell) = fun band symbol -> Symbol.to_html [ ("colspan", Html.Int band.alphabet.symbol_size_in_bits) ] symbol let (head_to_html: band -> symbol -> Html.cell) = fun band symbol -> Html.cell [] (Html.table [("bordercolor", Html.Color Color.green)] [ Html.row [] [ cell_to_html band band.head ] ] ) let (to_html: Html.options -> band -> Html.row) = fun options band -> let cells = (List.map (cell_to_html band) (List.rev band.left)) @ [ head_to_html band band.head ] @ (List.map (cell_to_html band) (band.right)) in Html.row options cells let (to_html_many: Html.options -> band list -> Html.table) = fun options bands -> let rows = List.map (to_html []) bands in Html.table (options @ [ ("bordercolor", Html.Color Color.white) ; ("cellpadding",Html.Int 1) ; ("cellspacing",Html.Int 0) ; ("border",Html.Int 1) ]) rows (* user *) let (pretty: t -> string) = fun t -> match Pretty.get_format() with | Pretty.Html -> to_html [] t | Pretty.Ascii -> to_ascii t end) (* Example of html produced by translation of a Band [A;B] into [ Tuple[1;0;0;1] ; Tuple[0;1;1;0] ] then into Band [1;0;0;1;0;1;1;0]
A B
1 0 0 1
1 0 0 1
1 0
0
1 0 1 1 0
*)