I watched this video on the composite pattern, where the main example is how to use the pattern as a mean to generate HTML code from a tree structure describing a todo list where each item can be in turn a todo list, and it seems a convenient test-bed, so here it is a target HTML:
[ ] Main
<ul>
<li>[ ] 1.</li>
<li>[ ] 2.
<ul>
<li>[ ] 2.1</li>
<li>[ ] 2.2</li>
</ul>
</li>
<li>[ ] 3.</li>
</ul>
(Sorry if the top [ ] Main
doesn't make sense, but I don't know HTML; furthermore that's irrelevant to my question, I believe.)
I understand that design patterns are mostly an OOP "thing", however I'm often referring to the article Design Patterns in Haskell to understand how they can be reinterpreted in functional programming, with the aim of understanding them at a deeper level.
As regards the composite pattern, that article essentially reads:
Composite. Recursive algebraic data types. Especially prominent since there's no built-in inheritance.
Therefore I thought it would be easy to try it in Haskell, and I came up with this code:
import Data.List (intercalate)
data Todo = Todo String | TodoList String [Todo] deriving Show
showList' :: Todo -> String
showList' (Todo s) = "[ ] " ++ s
showList' (TodoList s ts) = "[ ] " ++ s
++ "<ul><li>"
++ intercalate "</li><li>" (map showList' ts)
++ "</li></ul>"
which, fed like this
putStrLn $ showList' $ TodoList "Main" [Todo "1.", TodoList "2." [Todo "2.1", Todo "2.2"], Todo "3."]
generates this output
[ ] Main<ul><li>[ ] 1.</li><li>[ ] 2.<ul><li>[ ] 2.1</li><li>[ ] 2.2</li></ul></li><li>[ ] 3.</li></ul>
which is essentially the HTML at the top of my question rendered on a single line: it's clear from my implementation of showList'
that once a call to it (at any depth of the recusion) returns a string, that string is not altered in any way, just concateneted with others. So I feel that there's isn't much I can do to make showList'
add \n
and spaces to reach the nicely formatted HTML.
I've tried a bit, adding spaces and \n
, but especially upon reading Composite as a monoid by Mark Seemann I start do be a bit doubtful about the feasibility of what I'm trying to do...
I'm tempted to reach the conclusion that if composite is a monoid, it means that the various items are combined two by two in the same way regardless of their depth in the tree, and so this means that adding space for a nice formatting is not possible because the amount of space to be added depends on the context surrounding the two elements being concatenated, and not just on the two elements.
However, I'm not really sure about my reasoning, hence I'm asking here.
depth
parameter toshowList'
, use it for indentation and increase it on the inner/recursivemap (showLists' (depth+1))
call – Bookkeeping