;; simple histogram function
;; -*- mode: emacs-lisp -*-
;; Hans Halvorson
;; Time-stamp: <2006-10-17 11:01:01 hhalvors>
;; You may use or modify this in any way you wish
;; require Common Lisp package 'cl' for "lexical-let" in the
;; definition of histo
(require 'cl)
(defun histo (list)
"Given LIST, return a function that gives the number of times
that an object occurs in that list."
;; the lexical-let clause is needed to simulate lexical scope for the
;; variable 'list'
(lexical-let ((list list))
;; if LIST is empty, return the identically 0 function
(if (null list)
(lambda (x) 0)
(lambda (x)
;; pointwise addition of two functions: the characteristic
;; function of (car list), plus the function (histo (cdr
;; list))
(+
(if (= x (car list)) 1
0)
(funcall (histo (cdr list)) x)))
)
)
)
;; to apply the histo function do: (funcall (histo 'LIST) OBJECT)
;; Note: (histo 'LIST) is a function
(defun plusses (number)
"Given NUMBER, return a string of NUMBER '+' signs."
(let ((out-string ""))
(dotimes (i number)
(setq out-string (concat "+" out-string)))
out-string))
;; (defun plusses (number)
;; "Given NUMBER, return a string of NUMBER '+' signs."
;; (let ((m 0) (out-string ""))
;; (while (< m number)
;; (setq out-string (concat "+" out-string))
;; (setq m (+ m 1))
;; )
;; out-string
;; )
;; )
(defun histo-print (number-list &optional label)
"Print a histogram in buffer *histogram* from data in NUMBER-LIST, with an optional label."
(pop-to-buffer "*histogram*")
(if label
(insert (format "Histogram for data in %s.\n\n" label)))
;; lines have the form: 'NUMBER | +++++'
;; by default, the histogram ranges from 1 to 100 ... since I use this for grading
;; we have three different insertion clauses
;; (1) 100 is the only number with three digits
(insert (concat (number-to-string 100) " | " (plusses (funcall (histo number-list) 100)) "\n"))
;; (2) 99-10 are the numbers with two digits
(let ((a 99))
(while (> a 9)
(insert (concat " " (number-to-string a) " | " (plusses (funcall (histo number-list) a)) "\n"))
(setq a (- a 1))))
;; (3) 9-0 are the numbers with one digit
(let ((b 9))
(while (>= b 0)
(insert (concat " " (number-to-string b) " | " (plusses (funcall (histo number-list) b)) "\n"))
(setq b (- b 1))))
)
(defun buffer-to-list (buffer)
"Auxiliary function to transform a buffer of numbers into a
list of numbers."
(pop-to-buffer buffer)
(goto-char (point-min))
(setq die-liste '())
(while (search-forward-regexp "[0-9]+" nil t)
(setq die-liste (cons (string-to-number (match-string-no-properties 0)) die-liste)))
die-liste)
(defun histo-buffer (buffer)
"Given a BUFFER with numbers, return a new buffer *histogram*
with a histogram."
(let ((data (buffer-to-list buffer)))
(histo-print data buffer)))
;; Fact: the 'adder' function below works in Common Lisp, but not in
;; Emacs Lisp: this has to do with the fact that the former uses
;; lexical scope for variables, and the latter uses dynamic scope. We
;; can simulate lexical scope by using "lexical-let".
;; (defun adder (N)
;; (lambda (x)
;; (if (= x N) 1
;; 0)))
;; (adder N) should be the characteristic function of N.
;; (funcall (adder 2) 2)
;; => 1
;;
;; (funcall (adder 2) 3)
;; => 0