Baby’s First Web Application Framework
Deep in the depths of the DMP Lunar Bunker, I have a file server running. I prefer to do my computing on various internet connected devices rather than be tied to one computer. To this end, I try to keep my documents, images, and things of that nature centralized on the server so that I can get to it anywhere. This is all fine and good on a computer, but my iPad and various smartphones don’t have native support for mounting a smb share.
To that end, a project that I’ve had planned for a long time is to develop a web app running on my server to serve that stuff up through a web browser. That said, this post isn’t announcing the beginning of that project. I have enough on my plate: DMP Photo Booth still needs polish, I want to learn Haskell, I have a wedding to plan, and I have to spend this month figuring out what “Linear Algebra” is. Not to mention that the file server is in need of a software refresh. All of those things are higher priority. That said, as an excercise in learning Haskell, I’ve created a toy HTML generator.
That would be the name of my little suite of functions. I feel its name reflects the gravity of the project. All that it really is is a few types, and customized show instances. First, let’s take a look at my types:
type TagName = String type Attributes = [(String, String)] data Child = NullChild | TagChild Tag | StringChild String data Tag = NullTag | Tag TagName Attributes [Child]
First of all, forgive my sloppy indentation style. I haven’t really settled on a code style for Haskell yet. With that out of the way, let’s get to business.
This is just a type alias for a String. The concept of a math function is one that I understand, but I’ve always hated the trend of giving things useless names like
Σ instead of names like
Summation over. Sure, it was good enough for Aristotle, but I live in an age with things like “find and replace” and “code completion”. Maybe thousands of years from now, scholars will remember Chris Tetreault, father of the descriptive variable name. (HA!)
But I digress. I’ve created this alias to document when a String in a function argument or type constructor is a tag name.
This is a type alias for an array of String pairs. This type represents the attributes list of a Tag. Things like
src="https://doingmyprogramming.com/" It’s pretty self-explanatory. An empty list is an allowed value, and represents a tag with no attributes.
Now we’re getting a bit more complicated. If you picture a HTML document as a tree, then the child is the branches from the top level tag. There are three types of Child:
NullChild is the absence of a tag,
TagChild is a nested Tag,
StringChild is just some free floating text.
And now the meat of it.
Tag has two type constructors:
NullTag which is the absence of a tag, or
Tag takes 3 arguments: a
Attributes, and a list of
Child. This is all you really need to represent a basic HTML document. (no embedded CSS)
None of these types have
deriving(Show), because they require a custom implementation. Let’s look at that next.
First, let’s take a look at
Tag‘s Show implementation:
instance Show Tag where show NullTag = "" show (Tag n  ) = "<" ++ n ++ ">" show (Tag n a ) = "<" ++ n ++ flattenAttributes a ++ ">" show (Tag n  c) = show (Tag n  ) ++ foldl1 (++) (map show c) ++ "</" ++ n ++ ">" show (Tag n a c) = show (Tag n a ) ++ foldl1 (++) (map show c) ++ "</" ++ n ++ ">"
The show tag has 5 patterns:
- The first pattern is a
NullTag. It returns an empty string.
- The second pattern is a
Tagthat only has a
TagName. It places the
TagNamebetween angle brackets.
- The third pattern is one that also has an
Attributes. It flattens the
Attributes, and places it and the
TagNamebetween angle brackets
- The fourth pattern is one that has a
Childlist. It :
- Recursively calls
showwith the argument
(Tag n  ). This results in the opening tag being printed
Childlist, then folds the returned list of
Strings up using
foldl1 (++), concatenating all the returned
Strings into 1 large
- Closes the tag
- Recursively calls
- The fifth pattern has all fields. it works the same as the fourth, but calls the
show (Tag n a )instead.
The Show implementation for
Child is much simpler, and I don’t feel it requires explanation:
instance Show Child where show NullChild = "" show (TagChild x) = show x show (StringChild x) = x
But what about that
flattenAttributes function earlier? It looks like this:
flattenAttributes :: Attributes -> String flattenAttributes  =  flattenAttributes x = foldl (\acc (k,v) -> acc ++ " " ++ k ++ "=" ++ v) "" x
If given an Empty List, it returns an Empty List. In Haskell,
 is the same thing as
"", so this will function as an empty
String. However, if not given an empty string the work is much more complicated.
foldl is called.
foldl‘s function signature is:
(a -> b -> a) -> a -> [b] -> a, which reads as: “foldl takes a function that takes an a, b, and returns an a. It also takes an a, and a list of b, and it returns an a”. In english, it needs a starting value, a list to fold up, and a function to be called on each list element. I call
foldl on an empty string and
x, which is the
Attributes passed into the function.
The funky bit in the middle of all of that,
(\acc (k,v) -> acc ++ " " ++ k ++ "=" ++ v), is called a Lambda. If you’ve ever written an anonymous function in Java, you’ve done this before. The
\ at the beginning tells Haskell that what follows is a Lambda. After that, you have your arguments. Remember the signature of the function to be passed into
(a -> b ->a). In this lambda,
a, and this is a
b, a Tuple of two
Strings. The part following the
-> is the function body. In this lambda, we concatenate the two pairs together into the form of
" k=v". That is then concatenated onto
acc, which is the results of all previous calls. The final result looks something like
" k1=v1 k2=v2 ... kn=vn", which is returned from the function.
So, now that’s all done, and the
Tag type is usable. It’s not user friendly though:
Tag "html"  [TagChild $ Tag "head"  [TagChild $ Tag "title"  [StringChild $ "DMP"]], TagChild $ Tag "body"  [TagChild $ Tag "a" [("href","doingmyprogramming.com")] [StringChild "Doing My Programming..."]]] <html><head><title>DMP</title></head><body><a href=doingmyprogramming.com>Doing My Programming...</a></body></html>
Barf, right? It’s like writing HTML, only harder! Clearly we need some helper functions to make working with this easier.
tagHtml :: [Child] -> Tag tagHtml c = Tag "html"  c tagHead :: Attributes -> [Child] -> Tag tagHead a c = Tag "head" a c tagTitle :: String -> Tag tagTitle t = Tag "title"  [StringChild t] tagBody :: Attributes -> [Child] -> Tag tagBody a c = Tag "body" a c pageSkeleton :: String -> [Child] -> Tag pageSkeleton t b = tagHtml [TagChild $ tagHead  [TagChild $ tagTitle t], TagChild $ tagBody  b]
Here is some basic helpers I whipped up while writing this. These four helpers will take just the fields needed to produce their respective tags. Now, we can make a basic page skeleton by calling the
pageSkeleton "DMP" [TagChild $ Tag "a" [("href","http://doingmyprogramming.com")] [StringChild $ "Doing My Programming..."]] <html><head><title>DMP</title></head><body><a href=doingmyprogramming.com>Doing My Programming...</a></body></html>
While that could use some work, it’s enough to see where this is going. Much like Perl’s CGI module, functions can be created to automate much of the boilerplate.
Reinventing The Wheel
All this is fine and good, but surely this has been done already, right? Considering Haskell’s hackage server is implemented in Haskell, it seems that there is almost certainly a better web development framework for Haskell than doopHtml. I encourage you to not develop your next web application with the doopHtml framework, nor should you include your expertise in doopHtml on your resume.
It was good practice though!