Feeds:
Posts
Comments

Archive for the ‘Uncategorized’ Category

I was browsing the FileStore code and got to thinking that the FileStore data type rubbed me the wrong way because it hides IO, diluting the Purity of Essence of haskell’s precious type system.

In ghci of our code that uses FileStore:


:t darcsFileStore "/home/thartman/patchwiki/wikis/happstacktest/"
darcsFileStore "/home/thartman/patchwiki/wikis/happstacktest/" :: FileStore

I see that and I think, cool, a pure value.

Then I think — oops, wrong.


data FileStore
= FileStore {initialize :: IO (),
save :: forall a.
(Contents a) =>
ResourceName -> Author -> Description -> a -> IO (),
retrieve :: forall a.
(Contents a) =>
ResourceName -> Maybe RevisionId -> IO a,
delete :: ResourceName -> Author -> Description -> IO (),
rename :: ResourceName
-> ResourceName
-> Author
-> Description
-> IO (),
history :: [ResourceName] -> TimeRange -> IO [Revision],
latest :: ResourceName -> IO RevisionId,
revision :: RevisionId -> IO Revision,
index :: IO [ResourceName],
idsMatch :: RevisionId -> RevisionId -> Bool,
search :: SearchQuery -> IO [SearchMatch]}

Now I think, aha, this is OO in haskell.

So, what would I want instead?

First idea: how about something like


type FileStore = [resourceName] -- pure

and then a class of RepoAble or something like that which has a bunch of pure methods that must be implemented for any concrete instance of the class. (revision, latest, retrieve, history, index, idsMatch, search)
Then you would have some unavoidably impure methods like save, delete, rename.

Concrete instances could then be defined for Darcs, Git, Svn, etc. You basically have a nice wrapper over various types of repos.

On second thought though, maybe not such a good idea. To have everything work purely after an initial fetch, the FileStore value would have to contain everything in the repo. Nah.

I just want that darned FileStore value tagged with the IO type somehow so I can tell visually when looking at the code that we’re in impure land.

This is when I realized my mistake.

Since all the fields in FileStore are functions, there’s nothing impure about it after all. If one of the fields of fileStore had a concrete value related to a repo, this would smell wrong, because we’re mixing pure and impure — but that’s not the case here.

I think the confusion for me is that I am used to seeing “interfaces” in haskell defined in terms of implementation of a type class, but here the interface is just the arbitrary fields of a datatype, which I think is a bit less type safe.

So, I still think FileStore could be improved that way by taking advantage of typeclassing, but it’s not a matter of it being impure like I initially thought.

Read Full Post »

Oh boy howdy! Patch-tag just got a bunch of new features.

For starters, we have repo browsing built on gitit. This may sound like an easy thing to do, and we sure thought it would be before actually doing it, but it turned out to be quite a chore. Gitit has some memory issues, and no user permissioning model whatsoever. But we duked the memory issues out with the haskell profiler, cobbled together user permissioning with some help from Benja Fallenstein, and now… it works!

Well, browsing works, diffs works, and there’s a sane repo history viewer. Still no wikis. But we’ll get wikis working soon, too, you’ll see.

You can now browse private repositories with gitit too.

Also pushed:

Better error handling for emails, so hopefully no more severely belated registration emails.

Repo view is better.

You can no longer delete a repo by accidentally clicking the delete link. It’s now a submit button, and even that has a nag screen that tries to convince you that repo deletion is a Bad Thing.

Did I forget anything?

Oh, we ended phase wild alpha: unlimited users may now sign up.

Finally, some bad news for our few 1 users… you know who you are, you all got emails. It’s official now. We are phasing out Darcs 1. Existing darcs 1 repos still work for now, but we turned off creation of new darcs 1 repos, and are encouraging… well, forcing, everyone to move to darcs 2. In a bit — don’t worry, there’s still time. On the plus side, darcs 2 is better than darcs 1 in almost every way, so you should actually send us flowers and candy for twisting yalls arms. In all seriousness, dropping Darcs 1 was a tough call but we are being realistic. We have very ambitious plans for patch-tag, and serving multiple versions of darcs just seemed like something that would bog us down that very few people actually used, and the ones that did use it arguably shouldn’t be. To enjoy a beautiful garden, one must sometimes prune.

So, anyway — behold the new and improved Patch-Tag.

Enjoy!

Read Full Post »

To provide a wiki editing mechanism for repositories in Patch-Tag — which should eventually work for both darcs and git repos — we are adopting Gitit to our purposes by adding a security model with read and edit permissions for wikis, and making it posible for gitit to host more than one wiki at a time.

Overall development is proceeding smoothly, but one decision I regret is having used ImplicitParams for global-ish variables in the first version of our tweak.

ImplicitParams are evil!

They are evil in the same way that global variables are evil. It’s tempting to use them, because they seem to reduce some types of boilerplate. But it just takes a very few steps along that path before understandability becomes seriously impacted.

In fact, one of the best explanations i have seen of ImplicitParams (which actually argues for their goodness) is that IPs make it possible to have global variable-like behavior in haskell without using IOrefs, or other less tractable haskell98 solutions.

But when I look at the way we are using ImplicitParams in our gitit tweak, I am concluding that we shouldn’t be using IORefs *or* ImplicitParams, and basically should be staying away from globals altogether.

The bits of our program that are global-ish — basically configuration information for wiki requests and template key-value information for wiki display — should just be passed as a normal argument to the functions that need it. It’s a bit more wordy, but it tags every function that uses “global-ish” variables clearly, and I’ll take a big increase in understandability for a slight decrease in conciseness.

Exhibit A:


type ParamsHandler = (?params :: Params) => Handler

withMessages :: [String] -> ParamsHandler -> ParamsHandler
withMessages msgs val =
let ?params = ?params { pMessages = msgs ++ pMessages ?params }
in val

I look at this, notice that val doesn’t use anything defined in the let clause, and my brain shuts down.

Without implicit params:


withMessages :: Params -> [String] -> (Params -> Handler) -> Handler
withMessages params' msgs hndlr =
let params = params' { pMessages = msgs ++ pMessages params' }
in hndlr params

Maybe it’s just me, but I find the latter version much easier to understand.

Read Full Post »

Does anybody use git or darcs for versioning anything other than source code?

Personally, I version resumes and job applications, pictures of myself for quick avatar uploading (this is not all that clever given the alternatives of flickr / picassa, it’s just something I fell into), and craigslist postings for private purposes such as room rentals.

I guess it gives me peace of mind to be able to go back to an earlier version of something I was working on, regardless of whether it’s in a computer language or a human language. Am I weird?

Read Full Post »

« Newer Posts

Follow

Get every new post delivered to your Inbox.