使用Haskell状态monad代码气味? [英] Use of Haskell state monad a code smell?

查看:149
本文介绍了使用Haskell状态monad代码气味?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

上帝我讨厌术语代码气味,但我不能想到更准确的东西。

God I hate the term "code smell", but I can't think of anything more accurate.

我正在设计一个高级语言&编译器在我的业余时间空白了解编译器构造,语言设计和函数编程(编译器正在Haskell中编写)。

I'm designing a high-level language & compiler to Whitespace in my spare time to learn about compiler construction, language design, and functional programming (compiler is being written in Haskell).

在编译器的代码生成阶段,我必须在遍历语法树时维护状态数据。例如,在编译流控制语句时,我需要为要跳转的标签生成唯一的名称(从传入,更新和返回的计数器生成的标签,并且计数器的旧值不能再次使用) 。另一个例子是当我在语法树中遇到内联字符串字面量时,它们需要永久转换为堆变量(在Whitespace中,字符串最好存储在堆上)。我目前包装的状态monad的整个代码生成模块来处理这个。

During the code generation phase of the compiler, I have to maintain "state"-ish data as I traverse the syntax tree. For example, when compiling flow-control statements I need to generate unique names for the labels to jump to (labels generated from a counter that's passed in, updated, & returned, and the old value of the counter must never be used again). Another example is when I come across in-line string literals in the syntax tree, they need to be permanently converted into heap variables (in Whitespace, strings are best stored on the heap). I'm currently wrapping the entire code generation module in the state monad to handle this.

我被告知,编写一个编译器是一个很好地适合于函数范例,但是我发现我的设计方式与我在C语言中的设计方式(你真的可以用任何语言编写C,甚至是Haskell w / state monad)。

I've been told that writing a compiler is a problem well suited to the functional paradigm, but I find that I'm designing this in much the same way I would design it in C (you really can write C in any language - even Haskell w/ state monads).

我想学习如何在Haskell(而不是在函数范式) - 而不是C在Haskell语法。我应该真的尝试消除/最小化使用状态monad,还是它是一个合法的功能设计模式?

I want to learn how to think in Haskell (rather, in the functional paradigm) - not in C with Haskell syntax. Should I really try to eliminate/minimize use of the state monad, or is it a legitimate functional "design pattern"?

推荐答案

这意味着使用monads如State,ST或者定制的,或者只有一个包含状态数据的数据结构,你传递到几个地方,这不是一件坏事。 (实际上,monad只是帮助做这个!)但是,有状态,遍布的地方(是的,这意味着你,IO monad!)是一个难闻的气味。

This means that using monads such as State, ST or custom-built ones, or just having a data structure containing state data that you pass around to a few places, is not a bad thing. (Actually, monads are just assistance in doing exactly this!) However, having state that goes all over the place (yes, this means you, IO monad!) is a bad smell.

一个很明显的例子是,当我的小组正在进行 ICFP编程大赛2009 时, (代码位于git://git.cynic.net/haskell/icfp-contest-2009)。我们最终得到了几个不同的模块化部件:

An fairly clear example of this was when my team was working on our entry for the ICFP Programming Contest 2009 (the code is available at git://git.cynic.net/haskell/icfp-contest-2009). We ended up with several different modular parts to this:


  • VM:运行模拟程序的虚拟机

  • 控制器:读取模拟器输出并生成新控制输入的几组不同的例程

  • 解决方案:基于控制器的输出生成解决方案文件

  • 可视化程序:读取输入和输出端口并生成某种可视化或日志的几组不同的例程

每个都有自己的状态,并且它们通过VM的输入和输出值以各种方式交互。我们有几个不同的控制器和可视化器,每个都有自己不同的状态。

Each of these has its own state, and they all interact in various ways through the input and output values of the VM. We had several different controllers and visualizers, each of which had its own different kind of state.

这里的关键是,任何特定状态的内部限制它们自己的特定模块,并且每个模块甚至不知道其他模块的状态的存在。任何特定的有状态代码和数据集通常只有几十行长,有一些状态下的数据项。

The key point here was that the the internals of any particular state were limited to their own particular modules, and each module knew nothing about even the existence of state for other modules. Any particular set of stateful code and data was generally only a few dozen lines long, with a handful of data items in the state.

所有这些都粘在一起,函数,它没有访问任何状态的内部,并且当它循环通过模拟时仅仅按正确的顺序调用正确的东西,并且向每个模块传递非常有限量的外部信息以及模块以前的状态,当然)。

All this was glued together in one small function of about a dozen lines which had no access to the internals of any of the states, and which merely called the right things in the proper order as it looped through the simulation, and passed a very limited amount of outside information to each module (along with the module's previous state, of course).

当状态以这种有限的方式使用,类型系统阻止你无意中修改它,容易处理。

When state is used in such a limited way, and the type system is preventing you from inadvertently modifying it, it's quite easy to handle. It's one of the beauties of Haskell that it lets you do this.

一个回答说,不要使用monad。从我的角度来看,这是完全倒退。 Monads是一个控制结构,除其他外,可以帮助你最小化接触状态的代码量。如果你看看monadic解析器作为例子,解析的状态(即,正在解析的文本,它已经得到了多远,已经积累的任何警告等)必须通过解析器中使用的每个组合器。然而,只有几个组合器实际上直接操纵状态;任何其他使用这些几个功能之一。这样,您就可以在一个地方清楚地看到所有少量的代码,这些代码可以改变状态,并且更容易解释如何更改状态,从而使其更容易处理。

One answer says, "Don't use monads." From my point of view, this is exactly backwards. Monads are a control structure that, among other things, can help you minimize the amount of code that touches state. If you look at monadic parsers as an example, the state of the parse (i.e., the text being parsed, how far one has gotten in to it, any warnings that have accumulated, etc.) must run through every combinator used in the parser. Yet there will only be a few combinators that actually manipulate the state directly; anything else uses one of these few functions. This allows you to see clearly and in one place all of a small amount of code that can change the state, and more easily reason about how it can be changed, again making it easier to deal with.

这篇关于使用Haskell状态monad代码气味?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆