Configuration 在Erlang中实现图灵机
我有一个小项目,非常类似于实现图灵机器。我的基本问题是保存当前配置,例如头部位置和其他信息。对我来说,最重要的是保持头部姿势,让他向前或向后移动。解决这个问题的Erlang方法是什么Configuration 在Erlang中实现图灵机,configuration,erlang,state,turing-machines,Configuration,Erlang,State,Turing Machines,我有一个小项目,非常类似于实现图灵机器。我的基本问题是保存当前配置,例如头部位置和其他信息。对我来说,最重要的是保持头部姿势,让他向前或向后移动。解决这个问题的Erlang方法是什么 我对Erlang还不熟悉,但就我对OTP的了解而言,gen_事件行为适合这种情况。我的想法是越过最初的头部位置,然后通过一个手柄改变它。但我想还有更优雅的解决方案。与其他函数式语言一样,在Erlang中,您必须自己显式管理您的状态。这意味着您必须随身携带它,并在代码中穿行。它比听起来容易得多,很快就变成了第二天性
我对Erlang还不熟悉,但就我对OTP的了解而言,gen_事件行为适合这种情况。我的想法是越过最初的头部位置,然后通过一个手柄改变它。但我想还有更优雅的解决方案。与其他函数式语言一样,在Erlang中,您必须自己显式管理您的状态。这意味着您必须随身携带它,并在代码中穿行。它比听起来容易得多,很快就变成了第二天性 我个人会使用
genu服务器
行为,而不是genu事件
。它更具体,将为您的机器提供更好的支持。gen\u事件
比您需要的更一般。伊茂
gen_服务器
行为,实际上所有的行为,都为管理状态提供了支持。这些行为提供了顶级循环、接收和发送消息以及管理状态的基本功能。再加上很多你想要的额外的好东西,即使你还不知道
您可以通过提供回调函数来连接gen_服务器
,即所有行为,该行为在发生事件时调用回调函数。您给出了一个模块的名称,行为期望该模块包含回调。通常有固定数量的回调,例如gen_服务器
有6个,预定义的名称在特定时间调用
例如,有一个init/1
回调,在服务器启动时调用。它执行所有特定的初始化,然后返回{ok,State}
。这是服务器所需的状态。该行为管理此操作,并通过回调执行线程,并期望返回一个新的回调
例如,当您执行gen\u server:call(server,Message)
时,这将导致在服务器中使用以下参数和返回值调用handle\u call/3
回调:
handle_call(Message, From, State) --> {reply,Reply,NewState}
Reply
被发送回调用方,NewState
是更新状态,然后被传递到下一个回调
您可以在文档的和(例如和)部分中了解更多有关这方面的信息
在您的情况下,您可以让图灵机管理磁带、位置等,并向其发送命令。IMAO agin.我认为实施取决于您的期望。您可以对机器状态进行纯功能实现。您还可以将转换表作为函数或模块进行纯函数实现。最后,您可以使用OTP行为或不使用OTP行为在流程中封装任何内容 让我们从符号开始。它可以建模为原子,你可以选择空白的。它可以是atom
'0'
。它可以是一些花哨的名字blank
。如你所愿。我们可以在turing.hrl
中将其定义为常量
-define(BLANK, '0').
让我们继续磁带。一个优雅的实现是使用众所周知的zip结构。它将是三元组{LEFT,HEAD,RIGHT}
-module(tape).
-include("turing.hrl").
-export([new/0, read/1, write/2, left/1, right/1, tape2list/1]).
new() -> {[], ?BLANK, []}.
read({_, HEAD, _}) -> HEAD.
write({LEFT, _, RIGHT}, HEAD) -> {LEFT, HEAD, RIGHT}.
left({LEFT, HEAD, []}) -> {[HEAD|LEFT], ?BLANK, []};
left({LEFT, HEAD, [HR|RIGHT]}) -> {[HEAD|LEFT], HR, RIGHT}.
right({[], HEAD, RIGHT}) -> {[], ?BLANK, [HEAD|RIGHT]};
right({[HL|LEFT], HEAD, RIGHT}) -> {LEFT, HL, [HEAD|RIGHT]}.
tape2list({LEFT, HEAD, RIGHT}) -> lists:reverse(LEFT, [[HEAD]|RIGHT]).
现在我们可以进行机器实现了。让我们期望表实现为函数fun(STATE::any(),SYMBOL::any())->{NewSTATE::any(),NewSYMBOL::any(),'left'|'right'}
和机器状态,格式为{STATE,TAPE}。因此,可以将转换建模为函数next/2
。然后我们需要一个函数来确定某个状态是否接受状态fun(state::any())->boolean()
,然后我们可以提供模拟机器的函数,如go/3
、continue/3
和扩展版本go/5
以及打印机器状态的附加参数。打印功能可以管理自己的状态
-module(turing_machine).
-export([next/2, continue/5, continue/3, go/3, go/5, print_with_tape/2]).
next({STATE, TAPE}, F) when is_function(F, 2) ->
{NewSTATE, NewSYMBOL, Dir} = F(STATE, tape:read(TAPE)),
{NewSTATE, tape:Dir(tape:write(TAPE, NewSYMBOL))}.
continue({S, _} = St, Transition, IsAccepting, Print, PS) when
is_function(Transition, 2), is_function(IsAccepting, 1), is_function(Print, 2) ->
case IsAccepting(S) of
true -> St;
false ->
NSt = next(St, Transition),
continue(NSt, Transition, IsAccepting, Print, Print(NSt, PS))
end.
print({S, T}, _) ->
io:format("State: ~p, Head: ~p~n", [S, tape:read(T)]).
print_with_tape({S, T}, _) ->
io:format("State: ~p, Tape: ~p~n", [S, tape:tape2list(T)]).
continue(St, Transition, IsAccepting) ->
continue(St, Transition, IsAccepting, fun print/2, ok).
go(IS, Transition, IsAccepting) ->
go(IS, Transition, IsAccepting, fun print/2, ok).
go(IS, Transition, IsAccepting, Print, PS) ->
continue({IS, tape:new()}, Transition, IsAccepting, Print, PS).
然后,我们可以使繁忙的海狸机作为功能
BB = fun
('A', '0') -> {'B', '1', right};
('A', '1') -> {'C', '1', left};
('B', '0') -> {'A', '1', left};
('B', '1') -> {'B', '1', right};
('C', '0') -> {'B', '1', left};
('C', '1') -> {'HALT', '1', right}
end.
BBA = fun(S) -> S =:= 'HALT' end.
然后运行:
> turing_machine:go('A', BB, BBA).
State: 'B', Head: '0'
State: 'A', Head: '1'
State: 'C', Head: '0'
State: 'B', Head: '0'
State: 'A', Head: '0'
State: 'B', Head: '1'
State: 'B', Head: '1'
State: 'B', Head: '1'
State: 'B', Head: '1'
State: 'B', Head: '0'
State: 'A', Head: '1'
State: 'C', Head: '1'
State: 'HALT', Head: '1'
{'HALT',{['1'],'1',['1','1','1','1']}}
或者更奇特:
> turing_machine:go('A', BB, BBA, fun turing_machine:print_with_tape/2, ok).
State: 'B', Tape: [['0'],'1']
State: 'A', Tape: ['1',['1']]
State: 'C', Tape: ['1','1',['0']]
State: 'B', Tape: ['1','1','1',['0']]
State: 'A', Tape: ['1','1','1','1',['0']]
State: 'B', Tape: ['1','1','1',['1'],'1']
State: 'B', Tape: ['1','1',['1'],'1','1']
State: 'B', Tape: ['1',['1'],'1','1','1']
State: 'B', Tape: [['1'],'1','1','1','1']
State: 'B', Tape: [['0'],'1','1','1','1','1']
State: 'A', Tape: ['1',['1'],'1','1','1','1']
State: 'C', Tape: ['1','1',['1'],'1','1','1']
State: 'HALT', Tape: ['1',['1'],'1','1','1','1']
{'HALT',{['1'],'1',['1','1','1','1']}}
如果您希望将机器作为模块使用,可以通过将回调添加到turing\u machine.erl
-callback init_st() -> St::any().
-callback transition(St::any(), Symb::any()) ->
{NewSt::any(), NewSymb::any(), left|right}.
-callback is_accepting(St::any()) -> boolean().
还有一些附加的导出函数
-export([go_mod/1, go_mod/3, continue_mod/2, continue_mod/4]).
及其实现
go_mod(Mod) ->
go_mod(Mod, fun print/2, ok).
go_mod(Mod, Print, PS) ->
continue_mod(new_st(Mod:init_st()), Mod, Print, PS).
continue_mod(St, Mod) ->
continue_mod(St, Mod, fun print/2, ok).
continue_mod(St, Mod, Print, PS) ->
continue(St, fun Mod:transition/2, fun Mod:is_accepting/1, Print, PS).
而不是繁忙的海狸模块
然后它就可以用作
> turing_machine:go_mod(busy_beaver).
State: 'B', Head: '0'
State: 'A', Head: '1'
State: 'C', Head: '0'
State: 'B', Head: '0'
State: 'A', Head: '0'
State: 'B', Head: '1'
State: 'B', Head: '1'
State: 'B', Head: '1'
State: 'B', Head: '1'
State: 'B', Head: '0'
State: 'A', Head: '1'
State: 'C', Head: '1'
State: 'HALT', Head: '1'
{'HALT',{['1'],'1',['1','1','1','1']}}
甚至
> turing_machine:go_mod(busy_beaver, fun turing_machine:print_with_tape/2, ok).
State: 'B', Tape: [['0'],'1']
State: 'A', Tape: ['1',['1']]
State: 'C', Tape: ['1','1',['0']]
State: 'B', Tape: ['1','1','1',['0']]
State: 'A', Tape: ['1','1','1','1',['0']]
State: 'B', Tape: ['1','1','1',['1'],'1']
State: 'B', Tape: ['1','1',['1'],'1','1']
State: 'B', Tape: ['1',['1'],'1','1','1']
State: 'B', Tape: [['1'],'1','1','1','1']
State: 'B', Tape: [['0'],'1','1','1','1','1']
State: 'A', Tape: ['1',['1'],'1','1','1','1']
State: 'C', Tape: ['1','1',['1'],'1','1','1']
State: 'HALT', Tape: ['1',['1'],'1','1','1','1']
{'HALT',{['1'],'1',['1','1','1','1']}}
然后,您可以通过一种或另一种方式选择make it Process或OTP workers。谢谢您的回答!gen_事件行为以哪种方式更普遍?或者最大的区别在哪里?仅仅通过查看文档,我就认为gen_服务器适合双向通信,而gen_活动更面向国家。谢谢你的回答,你让我开心了!)
> turing_machine:go_mod(busy_beaver, fun turing_machine:print_with_tape/2, ok).
State: 'B', Tape: [['0'],'1']
State: 'A', Tape: ['1',['1']]
State: 'C', Tape: ['1','1',['0']]
State: 'B', Tape: ['1','1','1',['0']]
State: 'A', Tape: ['1','1','1','1',['0']]
State: 'B', Tape: ['1','1','1',['1'],'1']
State: 'B', Tape: ['1','1',['1'],'1','1']
State: 'B', Tape: ['1',['1'],'1','1','1']
State: 'B', Tape: [['1'],'1','1','1','1']
State: 'B', Tape: [['0'],'1','1','1','1','1']
State: 'A', Tape: ['1',['1'],'1','1','1','1']
State: 'C', Tape: ['1','1',['1'],'1','1','1']
State: 'HALT', Tape: ['1',['1'],'1','1','1','1']
{'HALT',{['1'],'1',['1','1','1','1']}}