> I think we all know this, but just to make sure the point is clear (in some > of the dicussion here, it doesn't seem that it is), the alternatives are > not only: > > (a) Source code with docstrings (or fancy formatted docstrings with links, > etc.) and sparse comments, but no other explanatory text anywhere. > > (b) Literate programming.
Actually, lisp has a long tradition of semicolon-style comments where ;;;; Chapter ;;; Section ;; Subsection ; Paragraph or inline With some Emacs hacking it would be possible to fold/unfold these comments. I worked on a Transputer editor that had fold/unfold and it was reasonably useful. I believe Emacs org-mode can also hide comments on command. Michael Fogus (The Joy of Clojure) is a better org-mode resource. John Kitchin (CMU professor) shows org-mode in his talk: http://www.youtube.com/watch?v=1-dUkyn_fZA I'm a "software blacksmith" and tend to create my own tools from scratch so I can't give advice on org-mode, IDEs or other "store-bought" solutions. :-) > Of course long chunks of text are needed to explain algorithms, motivation, > paths not taken, etc. Literate programming requires that those chunks be > inserted into the source file, and that you have to run the source file > through a filter to get rid of them. > ...[snip]... > > The point is that these days, at least, I don't *want* a lot of text in the > file that contains my source code, even though I think that explanatory > documentation is *very* important, and even though I'd guess that I've > written more of it per line of code than the average programmer. But > that's me. Others find LP extremely beneficial, and I support that > strategy for those who like it. > > (The desire to be able to see a lot of code at once is also one reason why > C-style code formatting is undesirable in a lisp language.) I used comment-style documentation method in my youth. I created a language, called KROPS, which was the implementation language for a large expert system. It was pure lisp on a Symbolics machine so there were no other documentation tools. This limited the style of comments to the conventions mentioned above. Returning to the code many years later (which is where LP really pays off) the comments were extremely helpful but not sufficient. KROPS uses a circular, self-modifying data structure which prints as a single, solid block of code. Documenting and diagraming this structure is necessary to understand it. ASCII tools are not sufficient for the diagrams but the current tools are. The code sat in long non-comment stretches. The comments that did exist tended to follow the semicolon style mentioned above. Overall the code follows a book-like convention but used pure source code. Snippets are attached below to show the style. Things to note are * The use of #|..|# (Common Lisp has 2 comment delimiter styles) * Higher organization of the comments - an intro to check that it works - a table of contents - the use of "levels" of semicolon structure - the use of docstrings on functions - the use of UPPERCASE in docstrings to highlight symbol names - the use of inline semicolons Not shown are long uninterrupted stretches of code containing only the docstring/uppercase and a few "inline" comments. So it is possible to do some form of reasonably well documented programming that is somewhat structured, involving only some discipline on commenting style. ==================================================================== #| ;; KROPS in common lisp ;; ;; Trivial test: ;; ;; initialize the system: ;; (PS-INITIALIZE) ;; ;; define the class TEST: ;; (LITERALIZE TEST A=) ;; ;; create one rule: ;; (P ASDF WHEN (TEST A= 1) THEN (PRINT "IT WORKS")) ;; ;; create one working memory element: ;; (MAKE TEST A= 1) ;; ;; look for the rule to fire: ;; (CS) ==> NIL.ASDF ;; ;; run one rule: ;; (RUN) ==> "IT WORKS" ;; ; STRUCTURE OF THIS FILE: ; 1.0 PACKAGE INFORMATION ; 2.0 VERSION VARIABLE ; 3.0 CHANGE LIST ; 4.0 IMPLEMENTATION PATCHES ; 5.0 DATA STRUCTURE DOCUMENTATION ; 5.1 RETE DATA STRUCTURES ; 5.1.1 R-NODE ; 5.1.2 NODES IN THE ALPHA RETE ; 5.1.2.1 R-A-PLAIN ; 5.1.2.2 R-A-OR ; 5.1.2.3 R-A-TRIG ; 5.1.2.4 R-B-A-DISTR ; 5.1.3 NODES IN THE BETA RETE ; 5.1.3.1 R-B-JOIN ; 5.1.3.2 R-B-SORT (sorted memory node) ; 5.1.3.3 R-B-P (PRODUCTION) NODES ; 5.1.4 OTHER DATA STRUCTURES ; 5.1.4.1 R-CS (A conflict set element) ; 5.1.4.2 R-B-COMMON (the vector portion of an R-B-JOIN node) ; 5.1.4.3 R-B-P-C (the vector portion of an R-B-P node) ; 5.1.4.4 R-B-ACC (an access vector) ; 5.1.5 MEMORIES ; 5.1.5.1 R-MEM (Rplacdable memory header) ; 5.1.5.2 R-MEM-ITEM (an element of R-MEM) ; 5.1.5.3 R-MEM-SORT (sorted memory) ; 5.1.5.4 R-UNIQUE ; 5.2 PARSER DATA STRUCTURES ; 5.2.1 INPUT SYNTAX ; 5.2.2 *RULE* ; 5.2.3 INTERNAL DATA STRUCTURES ; 5.2.3.1 PREDICATE ; 5.2.3.2 ORLIST ; 5.2.3.3 ANDLIST ; 5.2.3.4 TERM ; 5.2.3.5 TERMLIST ; 5.2.3.6 CENODE ; 5.2.3.7 ANDNODE ; 5.2.3.8 NOTNODE ; 5.2.3.9 SORTNODE ; 5.2.4 OUTPUT SYNTAX ; 5.3 COMPILER DATA STRUCTURES ; 5.3.1 *RHS-MAKES* ALIST ; 5.3.2 *PS-EXPRS* HASHTABLE ; 5.3.3 THE TOKEN ; 5.3.4 ACCESS FUNCTIONS ; 5.3.5 ACCESS PATHS ; 5.3.6 VARIABLES ; 5.4 OTHER DATA STRUCTURES ; 6.0 DEFVARS ; 7.0 DEFMACROS ; 7.1 GENERAL ; 7.2 PARSER ; 7.3 COMPILER ; 7.4 RETE FUNCTIONS ; 7.5 USER COMMANDS ; 7.6 RIGHT HAND SIDE MACROS ; 8.0 DEFUNS ; 8.1 GENERAL ; 8.2 PARSER ; 8.3 COMPILER ; 8.4 RETE FUNCTIONS ; 8.5 USER COMMANDS ; 9.0 TODO LIST |# ; 1.0 PACKAGE INFORMATION (provide :krops) (make-package :krops) (make-package :krep) ;(in-package 'krops :nicknames '(kb) :use :cl-user) (export '(attributep attributes-of cestack context context= cs defrule excise excise-module famo findrule firecount for-all-matches-of ge gt le lisp-value literalize lt make makev make-using make-usingv match matches maximize minimize modify modifyv ne nomatch opserror p p-context p-remove-context pprule ppwm priority *ps-all-rules* ps-initialize ps-such-that ps-remove ps-reset pwatch remove-all remove-match rjust run say same-type ps-select select-set strategy tabto then watch when window-hook wm wme-extract wme-class= wme-time-tag= wnltt & ! +=)) (use-package 'cl-user) ; 2.0 VERSION VARIABLE (defvar *ps-version* 0) (setq *ps-version* 2) (eval-when (eval load) (setf *features* (cons (intern (format nil "KROPS-VERSION-~a" *ps-version*) 'keyword) *features*))) #| ; 3.0 CHANGE LIST ;*********************************************************************** ;version 03: dos2unix ; untabify ; kb: to krep: ; remove krep package from shadowing-use-package call ;version 02: change use-package from lisp to cl-user ; add (make-package 'krep) ; remove use of ki, change to krep ; use keyword for package references ; remove symbolic, lucid, gclisp conditional code ;version 01: SBCL translation ;version 00: Conversion for Tires ;*********************************************************************** ;version 86: add version info to *features* list ;version 85: change eval-when to include eval ; 5.0 DATA STRUCTURE DOCUMENTATION ; 5.1 RETE DATA STRUCTURES ; The RETE is composed of two parts, the alpha part and the beta part. ; Alpha tests are tests that can be performed by referencing only one ; working memory element. Beta tests are tests that require more than ; one working memory element. Thus, ; (class attr= 1) ; would generate an alpha test because we need only index into the ; current working memory element to decide if some field in it has ; the value 1. But, ; (class1 attr= <x>) ; (class2 attr= <x>) ; would generate a beta test because we must look at two working memory ; elements to decide that their attr= fields match. ; ; There is one overall structure to a node in the rete network. ; This is called an R-NODE. ; 6.0 DEFVARS (defvar *attr-id* nil) (defvar *attr-ndx* nil) (defvar *beta-tests* nil) (defvar *ce-vars* nil) ; 7.0 DEFMACROS ; 7.1 GENERAL (defmacro add1 (arg) `(the fixnum (+ 1 (the fixnum ,arg)))) (defun parse-symbol (symbol) "PARSE-SYMBOL takes a krops symbol and breaks it into three parts if it contains a trailing = sign. The purpose is to return the ROLE FACET and ACCESS-FUNCTION for the symbol. There are two cases: ROLE.FACETNAME= form and the ROLE= form. In the first case the ROLE is assigned to the ROLE field, the FACET is assigned the FACETNAME and the access function is assigneda constructed GET-facetname form. In the second case the ROLE is assigned the ROLE, the facet defaults to VALUE and the ACCESS-FUNCTION is assigned GET-VALUE." (let ((role symbol) facet name access pos) (cond ((colonp symbol) (setq name (symbol-name symbol)) (cond ((eq symbol '*=) (setq role nil) (setq facet nil) (setq access nil)) ((setq pos (position #\. name)) (setq role (intern (subseq name 0 pos))) (setq facet (intern (subseq name (1+ pos) (1- (length name))))) (setq access (intern (concatenate 'string "GET-" (string-upcase facet)) (find-package 'krep)))) ('else (setq role (intern (subseq name 0 (1- (length name))))) (setq facet 'value) (setq access 'get-value))))) (values role facet access))) ... acres of code follow... -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.