@@ -0,0 +1,97 @@
1+---
2+title: CategoryBlog
3+what: explains how to use categories instead of tags
4+---
5+
6+## Categories
7+
8+Most people familiar with "tags" will also know the concept "categories".
9+
10+
11+
12+In fact, tags are harder to implement because they have to be represented as a
13+many-to-many relation, and categories are a simple 1-to-many relation.
14+
15+
16+
17+This is also the reason you can "simulate" categories using tags. In this
18+tutorial we will adapt the blog to use categories instead of tags. Here is
19+[a zip file](examples/categoryblog.zip) containing the files used in this
20+tutorial.
21+
22+## About category support
23+
24+Categories are simpler, but they are usually used in custom ways. That's why
25+Hakyll provides less "standard" functions to deal with them. But this gives us
26+another chance to learn some of the things we can do with Hakyll.
27+
28+## Reading Categories
29+
30+Tags are located in the `tags` metadata field. Since one post can only belong
31+in one category, a different approach was chosen here. The category of a post
32+is determined by the subfolder it is in. Here you see the directory layout for
33+our posts using categories:
34+
35+ posts
36+ |-- coding
37+ | |-- 2009-11-05-a-first-post.markdown
38+ | |-- 2009-11-28-a-third-post.markdown
39+ | `-- 2009-12-04-this-blog-aint-dead.markdown
40+ `-- random
41+ |-- 2009-11-10-another-post.markdown
42+ `-- 2009-12-23-almost-christmas.markdown
43+
44+Because we find all our posts in different subdirectories, sorting them is a
45+little harder: we still want them sorted by date, so it boils down to sorting
46+them by "base name". I hope it does not surprise you Hakyll provides a function
47+for that:
48+
49+~~~~~{.haskell}
50+postPaths <- liftM (reverse . sortByBaseName)
51+ (getRecursiveContents "posts")
52+~~~~~
53+
54+We reverse them again, because we want the most recent posts first. Now, we can
55+use the `readCategoryMap` function instead of `readTagMap`, which has the same
56+signature, but assigns categories based on the folders the posts are in.
57+
58+~~~~~{.haskell}
59+categoryMap <- readCategoryMap "categoryMap" renderablePosts
60+~~~~~
61+
62+The rest of the `hakyll.hs` is very similar to the one in the previous
63+tutorial, except we want to render a category list instead of a tag cloud.
64+
65+## Rendering a category list
66+
67+Because rendering a category list is quite easy, and it would be hard to
68+write a "general" function for this, hakyll does not provide such a function --
69+but it is not hard to write. First, we write an auxiliary function that produces
70+a list item for one category:
71+
72+~~~~~{.haskell}
73+categoryListItem category posts =
74+ "<li>" ++ link category (categoryToUrl category)
75+ ++ " - " ++ show (length posts) ++ " items.</li>"
76+~~~~~
77+
78+This is nothing more that some basic string concatenation to create a `li` HTML
79+element. The function that applies this on every element in the `TagMap` is more
80+interesting:
81+
82+~~~~~{.haskell}
83+categoryList :: HakyllAction TagMap String
84+categoryList = arr $ uncurry categoryListItem <=< toList
85+~~~~~
86+
87+This function might seem a little harder to understand if you are not familiar
88+with the `<=<` operator -- but it's just right-to-left monad composition in the
89+list monad. `uncurry categoryListItem <=< toList` is a pure function we want to
90+execute on the `TagMap`. But this is not possible in Hakyll[^1]. We need to make
91+an arrow of this function. The `arr` function solves this problem easily.
92+
93+[^1]: This is a feature, not a bug. It helps dependency handling.
94+
95+We then add this to our index page, and we are done. Feel free to hack around
96+with the source code. If you still have questions, feel free to ask them at the
97+[google discussion group](http://groups.google.com/group/hakyll).