我刚开始在Haskell玩游戏。经过多年的Ruby,我习惯了Ruby on Rails或Rugui使用的文件组织。
Haskell程序中是否有关于文件组织的指南,最佳实践或甚至框架?
(“了解你一个Haskell”和“真实世界Haskell”并没有真正解决这个问题。)
答案 0 :(得分:15)
haskell.org定义了两个可能有用的文件和目录布局,以及一些工具指南。
答案 1 :(得分:4)
主要限制是分层模块名称必须具有分层目录布局。
所以Data.Map.Fast进入Data / Map / Fast.hs
之后,将程序和库分解为逻辑单元,在单独的模块中,让依赖解析根据需要解析模块。
答案 2 :(得分:0)
我知道这是一个非常老的问题,但是作为一个初学者,我仍然没有找到令人满意的答案,而且关于如何布局项目的指导似乎也很少。
这是我发现有用的东西。
洞察力:
Haskell的声明性性质是与它的朋友和敌人。由于编译器确定方法的解析顺序,因此您只要遵循非常基本的规则(例如无循环依赖等),就可以使用任何想要管理复杂性的结构。基本上,编译器说,您可以管理自己的复杂性,我可以使任何事情成真。因此,代码复杂性成为逻辑上,话语上的复杂性,并且代码结构或多或少类似于在英语课堂上写论文或准备演讲。
我可能正在重新发明车轮,但是这里列出了一些我提出的技巧:
一般规则:将您的代码视为硬币,正面是纯净的部分,尾部是不纯净的部分。他们在一起但彼此不接触。在大多数情况下,您编写纯函数然后将其泛化为不纯函数,然后将这些定义保存在单独的文件中。
在代码的构建块上:
data
关键字构造的所有文件都应具有单独的文件。Primitive
或Model
或CustomType
的文件夹下。首选使用单数名称。当像import CustomType.MyString
而不是import CustomTypes.MyString
那样导入时,它们读起来更好。不过,这实际上是一个优先事项。toString
函数,则确实有助于确保作为此类的实例的type
也是具有{{1}的另一个类的实例}函数关于组织计算:
我从开发模式中注意到的是,在大多数情况下(至少对于小型应用程序),您会收到一个信号,并准备对此做出响应。此过程分解为三个子过程:
基本上,处理前两个问题的任何类型都有纯净的实例和不纯净的实例,也就是说,它们既要接受纯运算,也要包装在单子运算中。
第三点基于仅具有纯实例的类型。
这是我的一个小项目的摘录:
fromString
在扩展应用程序上:
不知道。可能有用的方法是定义特定于信号类型的原语,并使用诸如- README.md
- LICENSE
- docs/
- package.yml
- stack.yml
- Setup.hs
- tests/
- app/
- Main.hs
- src/
- Primitive/
- Definition/
- SomeType.hs
- Instance/
- Pure/
- SomeType.hs
- Impure/
- SomeType.hs
- FunctionDef/
- Pure/
- Setter.hs
- Impure/
- Setter.hs
- Control/
- Pure/
- SomeType.hs
- Impure/
- SomeType.hs
之类的通用容器与应用程序的其他部分进行通信。