Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

My question is one of structure and has two levels: (1) What is the best way to do it? and (2) What is the Haskell (functional) way to do it? 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.

The first structure that came to mind was something like this, where a ToDoList type object is simply a list of ToDo items:

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. 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?

like image 301
Pygmalion Avatar asked Dec 08 '10 01:12

Pygmalion


2 Answers

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. 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. In this particular case, id is a real function, so you shouldn't shadow it!

  • ToDoList is a single constructor datatype with one value; you probably actually just want a newtype or type synonym. (Exercise: rewrite the above snippet to work with a type synonym.)

  • You probably want an Ord instance on Priority and Status

like image 140
Edward Z. Yang Avatar answered Oct 14 '22 20:10

Edward Z. Yang


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

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.

Now, you should have no problems writing and reading all your values to a file, so long as they all derive Show and Read.

like image 34
Theo Belaire Avatar answered Oct 14 '22 22:10

Theo Belaire