Hi all, @Laurent
I haven't placed the code anywhere other than on my server. It was just an experiment in Clojure but I'm glad it's useful to others. I'll go ahead and make it open source and let you know when I do. It should be relatively robust as it is -- I ran it through some of the src Clojure libraries and they look as intended. The only change I intended to make and never did was to apply the "defn" style to all types of defs. I'll probably do that before releasing the code on a repo. @Rick I experimented with many different versions of this before I came to the "large function" format. At first I tried doing it completely regex which failed miserably. One intention, which I felt would be much more functional-like, was to split up the code into a list of functions. For example, code that starts like this: (defn plus-five [n] (+ 5 n)) Would end up something like this after my parsing: (format-list "(" (format-def "defn") " " (format-func-name "plus- five") " [" (format-param-list "n") "] " (format-list "(" (format-func- name "+") " 5 n)" ) ")" ) It seems wieldy when I write it out but now that it's all parsed as a list it would be trivial to implement each of those format- functions and eval the entire thing to generate your desired HTML. My code didn't start off large, of course. What I did was work incrementally. First I figured out how to detect string starting and ending since that seems the simplest. I knew that there had to be some sort of "state" so that we know when we encounter a quote whether or not it is the end of a string we've already begun reading. I realized that in functional languages we already have a stack given to us -- the function stack. So, the next step for me was to see if I could make this approach work by hopping back and forth between functions. I got fairly far into this before I had problems with stack overflows. I found out later than I needed knowledge of trampoline and mutual recursion to solve the issue. I think the approach still has potential but the setback forced me to consider other options. This lead me to implement the stack local in the recursive definition of parse-code. After I got strings working, it was mostly smooth sailing until I got to the point where I wanted to highlight the names of variables after "def" and "defn". Now my approach of reading a character at a time was becoming quite unorganized. After some more thought experiments, I decided to give the stack an upgrade and go with a struct to record state instead of just a keyword. Now I could actually put values on the stack and therefore keep track of, for example, the first element of the list that an element is contained in. Continuing down this path, along with incremental updates, led the code to where it is now. I did use the REPL extensively to test each new feature. I don't use an emacs-like editor at all, I coded it in Notepad++. I would simply paste each snippet of code into the REPL as I write it to make sure that it works in basic cases. I also used load-file quite often to run the entire program against sample input and especially itself. In summary, the "large function" approach wasn't an end goal, it was just a result of incremental progress. I don't know if it's Clojure- like which is a big reason that I asked for advice on my first post. I haven't received any criticism about that yet so I assume it's not a bad approach. Even though it seems lengthily, it reads linearly and doesn't have logic scattered in pieces all around. In the end, I think that's what functional programming is about anyway. ~ Kai On Jul 2, 6:48 am, Rick Moynihan <rick.moyni...@gmail.com> wrote: > 2009/6/26 Kai <poki...@gmail.com>: > > > > > > > Hi all, > > > I'm new to this discussion group and Clojure. I'm sharing the first > > "bigger-than-REPL" script that I've written because I haven't seen > > anything else like it for Clojure. It's a script that takes Clojure > > code as input and generates a pretty HTML version. You can view it > > here (I ran the script through itself): > > >http://kai.myownsiteonline.com/clojure/html.clj.html > > > The style sheet is kept separate for cases with more than one Clojure > > script shown on a page. Also, it still formats just as well without > > the javascript; the javascript only contains code that highlights > > Clojure script as you mouse over it. > > > I don't have any particular intention by creating this script, it was > > just a warmup into Clojure. Feel free to use it for whatever purpose. > > I'd appreciate comments on the coding style as well as how to make it > > faster - core.clj takes a good 10 minutes! It was a pain and a > > pleasure to code :) > > Cute! > > Though I've spent a lot of time over the last 6 months reading about > and toying with clojure, I've not yet found the time to write anything > even as substantial as this. I did however take a quick look at the > code, and it seems reasonably easy for a noob such as myself to > follow. > > That said, it did remind of something I was meaning to ask which > concerns large function definitions (here and elsewhere e.g. > clojure.core). > > Your parse-code function definition seems quite long and it seems > counter to the way I think I would write this program; as I would be > inclined to write lots of smaller functions responsible for emitting > the different spans for comments, strings, etc; and then tie them up > into a larger function. That way I could evaluate them all separately > and combine them later. > > I have seen similar large functions elsewhere e.g. a few in > clojure.core, and my question is: > > How do you go about writing a large function like this? What is the > process involved? I realise referential transparency means that > almost every s-exp is evaluatable separately (providing the necessary > bindings are in scope) but is it not a hassle to build such things? > How is it you compose a large function and get the benefits of the > REPL and lisps interactive development model? Do you evaluate these > snippets in a let bind? If so what tools support this? > > I'm also curious as to what the pro's are in writing large functions > like this. There are several in clojure.core, I think gen-class is > the one that springs to mind; why is this not defined as a series of > smaller functions? > > Thanks again for the HTML pretty printer! > > R. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---