Haskell的规模设计?
设计/构造大型函数程序的好方法是什么,特别是在Haskell中?
我经历了一系列的教程(写自己的计划是我最喜欢的,Real World Haskell紧随其后) - 但大多数程序都是相对较小的,而且是单一用途的。 另外,我不认为其中的一些特别优雅(例如,WYAS中的大量查找表)。
我现在想写更大的程序,更多的移动部分 - 从各种不同的来源获取数据,清理它,以各种方式处理它,在用户界面中显示它,坚持它,在网络上进行通信等。一个最好的结构,这样的代码要清晰易读,可维护,并且适应不断变化的需求?
有相当多的文献针对大型面向对象的命令式程序来解决这些问题。 像MVC,设计模式等理念是实现广泛目标的体面处方,如OO风格的分离关注点和可重用性。 此外,较新的命令式语言适合于“设计成长”的重构风格,在我的新手观点中,Haskell显得不太合适。
Haskell有相当的文献吗? 功能性程序设计(单子,箭头,应用等)中的外来控制结构的动物园如何最适用于此目的? 你可以推荐哪些最佳实践?
谢谢!
编辑(这是唐斯图尔特回答的后续):
@dons提到:“Monads可以捕获类型中的关键架构设计。”
我想我的问题是:如何以纯粹的功能语言来思考关键架构设计?
考虑几个数据流的例子,以及几个处理步骤。 我可以将数据流的模块化分析器编写为一组数据结构,并且我可以将每个处理步骤作为纯函数来实现。 一块数据所需的处理步骤取决于其值和其他值。 其中一些步骤应该跟随GUI更新或数据库查询等副作用。
以合适的方式将数据和解析步骤联系起来的“正确”方法是什么? 人们可以编写一个大功能,为各种数据类型做正确的事情。 或者可以使用monad来跟踪到目前为止已处理的内容,并让每个处理步骤从monad状态下一步获得所需内容。 或者可以编写大量单独的程序并发送消息(我不太喜欢这个选项)。
他链接的幻灯片有一个东西我们需要的项目符号:“用于将设计映射到类型/函数/类/ monads上的习语”。 成语是什么? :)
我在Haskell的工程大型项目以及XMonad的设计和实现中谈了一些这方面的内容。 大型工程是关于管理复杂性的。 Haskell中用于管理复杂性的主要代码结构化机制是:
类型系统
分析器
纯度
测试
Monads的结构
输入类和存在类型
并发性和并行性
par
到你的程序打,方便,可组合并行的竞争。 重构
明智地使用FFI
元编程
包装和分销
警告
-Wall
让你的代码保持清新的气味。 你也可以看看Agda,Isabelle或Catch寻求更多的保证。 对于类似皮棉的检查,请参阅伟大的hlint,这将提出改进建议。 借助所有这些工具,您可以随时掌握复杂性,尽可能多地移除组件之间的交互。 理想情况下,你有一个非常大的纯代码库,这很容易维护,因为它是合成的。 这并非总是可行,但值得一试。
一般来说: 将系统的逻辑单元分解成可能的最小的透明元件,然后在模块中实现它们。 组件集合(或内部组件)的全局或本地环境可能会映射到monads。 使用代数数据类型来描述核心数据结构。 广泛分享这些定义。
Don给了你上面大部分的细节,但是这是我在做Haskell的系统守护进程等真正有价值的有状态程序时的两分钱。
最后,你住在monad变压器堆栈中。 最后是IO。 在此之上,每个主要模块(抽象意义上而不是单元模块意义上的)将其必要状态映射到该堆栈中的一个层。 因此,如果你的数据库连接代码隐藏在一个模块中,你可以将它全部写入MonadReader Connection m => ... - > m ...类型,然后你的数据库函数总是可以在没有其他函数的情况下获得它们的连接模块必须知道它的存在。 你可能最终会得到一层承载你的数据库连接,另一个你的配置,第三个你的各种信号量和mvars用于解决并行和同步,另一个你的日志文件处理等。
首先找出你的错误处理。 Haskell在大型系统中最大的弱点是大量的错误处理方法,包括糟糕的错误处理方法(这是错误的,因为你无法返回任何错误信息;除非你真的使用Either而不是Maybe只是意味着缺失值)。 弄清楚你将如何首先完成它,并从你的库和其他代码使用的各种错误处理机制中设置适配器到最终的适配器中。 这会在以后拯救你一个悲伤的世界。
附录 (摘自评论;感谢Lii&liminalisht) -
更多讨论关于将大型程序切割成单片机的不同方式:
本Kolera给出了一个很大的实用介绍到这个话题,和布赖恩·赫特讨论解决的问题lift
荷兰国际集团一元行动统一到您的自定义单子。 乔治威尔逊展示了如何使用mtl
编写与任何实现所需类型类的monad(而不是您自定义的monad类)兼容的代码。 Carlo Hamalainen写了一些总结乔治谈话的简短有用的笔记。
在Haskell中设计大型程序与在其他语言中进行设计没有什么不同。 大规模的编程就是将你的问题分解成易于管理的部分,以及如何将它们融合在一起; 实现语言不那么重要。
也就是说,在一个大型设计中,尝试和利用类型系统以确保您只能以正确的方式将您的作品放在一起。 这可能涉及新类型或幻像类型,使看起来具有相同类型的东西不同。
在进行代码重构时,纯度是一个很大的好处,所以尽量保持尽可能纯的代码。 纯代码很容易重构,因为它与程序的其他部分没有隐藏的交互。
链接地址: http://www.djcxy.com/p/1141.html