简体   繁体   English

程序结构 - 简单的命令行待办事项应用程序 - 什么是Haskell方式?

[英]Program Structure — Simple Commandline To Do List App — What's the Haskell way?

Background: I am working on my first complete program in Haskell, a simple to do list application on the command line. 背景:我正在使用Haskell中的第一个完整程序,这是命令行中的一个简单的待办事项列表应用程序。

My question is one of structure and has two levels: (1) What is the best way to do it? 我的问题是结构问题,有两个层次:(1)最好的方法是什么? and (2) What is the Haskell (functional) way to do it? (2)什么是Haskell(功能)方法呢? The reason I phrase it this way is because I suspect that there may be a faster or easier way to do it that ignores the principles of functional programming. 我这样说的原因是因为我怀疑可能有一种更快或更简单的方法来忽略函数式编程的原理。 I'd like to do it in the more elegant and clear way, as it is more of a learning exercise than anything else. 我想以更优雅和清晰的方式做到这一点,因为它更像是一种学习练习而不是其他任何东西。

Keep in mind that I'd (obviously) like the application to be somewhat persistent. 请记住,我(显然)喜欢应用程序有点持久。 The two options on the table right now are to store information in a flat text file or alternately in a Sqlite database. 现在表上的两个选项是将信息存储在平面文本文件中,或者交替存储在Sqlite数据库中。

The first structure that came to mind was something like this, where a ToDoList type object is simply a list of ToDo items: 想到的第一个结构是这样的,其中ToDoList类型对象只是ToDo项的列表:

import Data.List
import Data.Time

data ToDo = ToDo {
        todoId       :: Int,
        todoDue      :: ZonedTime,
        todoCreated  :: UTCTime,
        todoItem     :: String,
        todoPriority :: Priority,
        todoStatus   :: Status
        }
        deriving (Show, Read)

type ToDoList = [ToDo]

data Priority = Low | Medium | High
        deriving (Show, Read, Eq, Ord)

data Status = Complete | InProgress | Open
        deriving (Show, Read, Eq, Ord)

But then I began to wonder how best to store objects of this type. 但后来我开始想知道如何最好地存储这种类型的物体。 Would this imply that I store them in a flat file? 这是否意味着我将它们存储在一个平面文件中? Is there some way to relate objects of highly specified types like this to fields/columns in a database? 有没有办法将像这样的高度指定类型的对象与数据库中的字段/列相关联?

When I think about using a Sqlite database, it seems that all of the work will be done in the database calls, and Haskell types will have comparatively little to do with it. 当我考虑使用Sqlite数据库时,似乎所有的工作都将在数据库调用中完成,而Haskell类型将与它相关性很小。 This seems bad. 这看起来很糟糕。

In summary, the question is how best can I model the data structure of my simple to do list application in keeping with the notions of functional programming and Haskell ideals that I am seeking to practice with this project? 总之,问题是如何最好地模拟我的简单待办事项列表应用程序的数据结构,以符合我想要在这个项目中实践的函数式编程和Haskell理想的概念?

The Show/Read combination is a tremendously easy way of serializing and deserializing the internal state of your application, and because of purity it basically always works too. Show / Read组合是一种非常简单的序列化和反序列化应用程序内部状态的方法,并且由于纯度,它基本上总是有效。 Furthermore, you'll get good practice writing functions that slice and dice lists, since you'll be able to treat the list as if it is entirely loaded into memory (and maybe if you want to play with some more efficient data structures, you can look at ways to optimize different queries.) 此外,您可以很好地编写切片和骰子列表的函数,因为您将能够将列表视为完全加载到内存中(并且如果您想要使用更高效的数据结构,那么您可以查看优化不同查询的方法。)

For example, if I want to find all items that are due before some date, I can write this using a filter on due: 例如,如果我想在某个日期之前找到所有到期的项目,我可以使用过滤器来写这个:

dueBefore (ToDoList ts) d = ToDoList (filter (\t -> due t <= d) ts)

Some style nitpicks on your pseudocode: 你的伪代码上的一些样式挑剔:

  • Since all accessor functions (id, die. created...) get dumped into the module-wide namespace, it's good style to prefix/suffix them with the name of the record, such as todoId, todoDie. 由于所有访问器函数(id,die。created ...)都被转储到模块范围的命名空间中,因此使用记录名称(例如todoId,todoDie)为它们添加前缀/后缀是一种很好的方式。 In this particular case, id is a real function, so you shouldn't shadow it! 在这种特殊情况下, id是一个真正的函数,所以你不应该暗示它!

  • ToDoList is a single constructor datatype with one value; ToDoList是一个具有一个值的构造函数数据类型; you probably actually just want a newtype or type synonym. 你可能实际上只是想要一个newtype或类型同义词。 (Exercise: rewrite the above snippet to work with a type synonym.) (练习:重写上面的代码片段以使用类型同义词。)

  • You probably want an Ord instance on Priority and Status 您可能需要优先级和状态的Ord实例

I think that a flat file will make your life easier, and will work just as well, unless you have such a terrible backlog of work that you need a database to hold it all ;P 我认为一个平面文件会让你的生活变得更轻松,并且同样会起作用,除非你有如此可怕的积压工作,你需要一个数据库才能完成所有工作; P

I would recomend reading Learn You a Haskell for Great Good , or at least, this chapter . 我会建议阅读“ 了解大好事” ,或者至少是本章 It even contains a short TODO application similar to what you are trying to write. 它甚至包含一个类似于您尝试编写的简短TODO应用程序。

Now, you should have no problems writing and reading all your values to a file, so long as they all derive Show and Read. 现在,你应该没有问题写入和读取所有的值到一个文件,只要他们都得到显示和阅读。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM