Configuration 在Erlang中实现图灵机

Configuration 在Erlang中实现图灵机,configuration,erlang,state,turing-machines,Configuration,Erlang,State,Turing Machines,我有一个小项目,非常类似于实现图灵机器。我的基本问题是保存当前配置,例如头部位置和其他信息。对我来说,最重要的是保持头部姿势,让他向前或向后移动。解决这个问题的Erlang方法是什么 我对Erlang还不熟悉,但就我对OTP的了解而言,gen_事件行为适合这种情况。我的想法是越过最初的头部位置,然后通过一个手柄改变它。但我想还有更优雅的解决方案。与其他函数式语言一样,在Erlang中,您必须自己显式管理您的状态。这意味着您必须随身携带它,并在代码中穿行。它比听起来容易得多,很快就变成了第二天性

我有一个小项目,非常类似于实现图灵机器。我的基本问题是保存当前配置,例如头部位置和其他信息。对我来说,最重要的是保持头部姿势,让他向前或向后移动。解决这个问题的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']}}