这是我前一个问题的后续问题:State and IO Monads
我的目标是为文件创建一个简单的文本编辑器。我已经有了一个Editor
组件,可以很好地封装基础数据结构上的所有编辑操作。
感谢上一个问题的答案,我能够重构我的程序,以便我现在有一个很好的monad变换器堆栈:
type Session = StateT AppState (StateT Editor IO)
AppState
保存应用程序的全局状态(当前打开文件等),而Editor
表示应用程序编辑组件的内部状态(插入符号所在的位置)等等......)我有一个函数是应用程序的主要驱动程序:
eventLoop :: Session ()
到目前为止一直很好,但是现在我不知道如何从main
函数启动变换器堆栈? Main必须返回IO
monad中的某个东西,它位于我的堆栈的最底层。我的猜测是我必须初始化AppState
,然后执行以下操作:
main = do
let initialAppState = ...
return $ runStateT eventLoop initialAppState
但是我现在在哪里初始化Editor
?
令我困惑的是,在重构之前,Editor
只是AppState
的成员:
data AppState = { editor :: Editor , ... }
但现在它已经移出AppState
并成为变压器堆栈的某个兄弟。 Editor
不应该AppState
仍然是Session
的一部分,因为修改它意味着修改整体状态吗?
如何使用AppState
和Editor
正确初始化main
,然后从我的<table class="table table-condensed table-bordered table-hover">
<tr>
<th>Report</th>
<th>Type</th>
<th>Date</th>
</tr>
@foreach($tableContent as $data)
<tr>
<td><input type="checkbox" name="report" value="reportValue" id="{{$data->id}}" >{{$data->title}} </input></td>
<td><b>{{$data->report_type}}</b></td>
<td>{{$data->created_at}}</td>
</tr>
@endforeach
</table>
<a class="btn btn-default" href="/deletereport/"{{--how do I get checked box id here ? --}}">Delete</a>
运行它?
答案 0 :(得分:2)
我如何从主函数中启动变压器堆栈?
main =
flip evalStateT initialAppState $
flip evalStateT initialEditorState $
eventLoop
where
initialAppState =
error "Define me"
initialEditorState =
error "Define me"
编辑器是否仍然是AppState的一部分,因为修改它意味着修改整体状态?
取决于。
请记住,Monad Transformer的目的是以临时方式扩展功能吗? ad-hoc我的意思是,不重写现有的代码库,而是添加它。因此,如果您已经拥有了编辑器和AppState的隔离API,那么将它们组合到另一个&#34; dome&#34;中会更容易。模块使用变压器堆栈。
OTOH,从最初的架构角度来看,AppState是一个包含编辑器(我将其命名为EditorState)的数据结构等等,这是完全有道理的。在这样的cas中,AppState的API应该封装Editor的API。 &#34;镜头&#34;库将帮助您使用这种复合数据结构(尽管我必须提到它有一个陡峭的学习曲线)。