130 likes | 334 Views
Функциональное программирование. Факультет инноваций и высоких технологий Московский физико-технический институт. Лекция 20. Пример: реализация машины Тьюринга. Интересное упражнение. Реализуем Машину Тьюринга на функциональном языке MT = <A,S,P,L,s 0 >, где
E N D
Функциональное программирование Факультет инноваций и высоких технологий Московский физико-технический институт
Лекция 20 Пример: реализация машины Тьюринга
Интересное упражнение • Реализуем Машину Тьюринга на функциональном языке • MT = <A,S,P,L,s0>, где • A - алфавит (мы предполагаем char) • S - множество состояний (int) • L – полубесконечная лента с текущей ячейкой (n(int→A)) • s0S – начальное состояние (0) • P – программа, состоящая из <s,c,c’,s’,a> • s,c – состояние + видимый символ, определяет выполняемую команду • c‘ – новый символ, записываемый вместо старого • s‘ – новое состояние, в которое переходит машина • a – действие (L,R – сдвиг влево-вправо;U – на месте; H-останов)
Пример: сложение двоичных чисел • (0,'0','0',0,R); • (0,'1','1',0,R); • (0,' ',' ',1,R); • (1,'0','0',1,R); • (1,'1','1',1,R); • (1,' ',' ',2,L); • (2,'1','0',3,L); • (2,'0','1',2,L); • (2,' ',' ',5,R); • (3,'1','1',3,L); • (3,'0','0',3,L); • (3,' ',' ',4,L); • (4,'1','0',4,L); • (4,'0','1',0,R); • (4,' ',' ',0,R); • (5,'1',' ',5,R); • (5,' ',' ',5,H)
Определение типов type state = int*int;; type base = char;; type ribbon = int -> base;; type op = L | R | U | H;; type instr = state * base * base * state * op;; type program = instr list;; type MT = program * state * ribbon;; let mtadd = ( [ (0,'0','0',0,R); (0,'1','1',0,R); (0,' ',' ',1,R); (1,'0','0',1,R); (1,'1','1',1,R); (1,' ',' ',2,L); (2,'1','0',3,L); (2,'0','1',2,L); (2,' ',' ',5,R); (3,'1','1',3,L); (3,'0','0',3,L); (3,' ',' ',4,L); (4,'1','0',4,L); (4,'0','1',0,R); (4,' ',' ',0,R); (5,'1',' ',5,R); (5,' ',' ',5,H)], (0,0),mkrib "001110 101");;
Один шаг выполнения let step (P,(sym,st),rib) = let s = rib sym in let (_,_,nchr,nst,cmd) = List.find(fun (q,c,_,_,_) -> (q=st)&&(c=s)) P in let nsym = proc sym cmd in (P,(nsym,nst),ins nchr sym rib);; let proc n = function R -> n+1 | L -> n-1 | U -> n | H -> -1;; let ins c n rib = fun x -> if n=x then c else rib x;; let empty = fun x -> ' ';;
Выполнение программы – фиксированная точка от step let terminal MT = match MT with (_,(n,_),_) when n<0 -> true | _ -> false;; let rec run MT = if terminal MT then MT else let n = step MT in let _ = print n in run (n);; let print (P,(sym,st),rib) = let aux n i (c:char) = if i=n then "["+c.ToString()+"]" else c.ToString() in printfn "q=%2d, p=%2d %s" st sym ([ for i in 0..10 -> aux sym i (rib i) ] |> List.fold_left(fun ac c -> ac+c) "");; let mkrib (s:string) = let rec f n = function [] -> empty | h::t -> ins h n (f (n+1) t) in s.ToCharArray() |> List.of_array |> (f 0);;
Что мы сделали? • Проделанное упражнение доказывает, что любая вычислимая по Тьюрингу функция вычислима в λ-исчислении • Поскольку мы нигде не использовали конечность ленты
Улучшения • В приведенной реализации по ходу выполнения растет сложность доступа к ленте • Возможно использование более эффективных структур: • Массив с произвольным доступом (F#) • Дерево • Зиппер (2 списка – левая и правая полулента)
Зиппер type 'a zipper = 'a list * 'a list;; let left (l,r) = match l with [] -> ([],' '::r) | x::t -> (t,x::r);; let right (l,r) = match r with [] -> (' '::l,[]) | x::t -> (x::l,t);; let norm (l,r) = match r with [] -> (l,[' ']) | _ -> (l,r);; … A B C D E F ([’C’;’B’;’A’],[’D’;’E’;’F’])
Машина Тьюринга с молнией let step (P,st,rib) = let (l,x::r) = norm rib in let (_,_,nchr,nst,cmd) = List.find(fun (q,c,_,_,_) -> (q=st)&&(c=x)) P in let nrib = proc (l,nchr::r) cmd in (P,nst,nrib);; let proc n = function R -> right n | L -> left n | U -> n | H -> ([],[]) ;;
Мораль • Для функционального программирования характерны специфические структуры данных • Из-за отсутствия памяти с «прямым» доступом • Из-за того, что в идеале все структуры immutable • Окасаки, Purely Functional Data Structures