Sunday, May 31, 2009

motivation for Andand.NET

Some of my followers on twitter encouraged me to post about my andand implementation, so here is the first in a series.

In brief: I wanted to replace

if (a != null && a.b != null && a.b.c != null) {
return a.b.c.d;
}
else {
return null;
}

by

return andand(a.b.c.d);

and I manged to learn a little bit about monads, generalized algebraic data types, and .NET on the way to achieving

return andand(() => a.b.c.d)


About a month ago I was working with an instance of a generic type:

var page = Potpourri.Page.getPage(s, count.Value);
ViewData["reverse-memento"] = page.reverseMemento.itemNumber;

This code obtains a range of rows from a database given a starting position and a window size. Simple integer offsets don't work for the general case of concurrent access by lay users to a mutable table. My approach requires getPage to know an equivalence relation on elements, but it doesn't require that getPage know about itemNumber specifically or even that there be just one field/property that's sufficient to determine equality.

So, AFAICT, there's no good way to avoid violating Demeter here.

Certainly there remains a practical problem that the next and previous page references could be undefined for any given page. In this case, reverseMemento could be null.

The awkward conditional needed to avoid NullReferenceException here brought to mind Object#andand. Informally, andand provides short-circuit behavior for chained accesses. The Ruby andand relies on Ruby metaprogramming features. The closest thing we have to a macro facility in c# is Linq expression trees, and I hadn't had an excuse to use System.Linq.Expressions yet, so this seemed like a good opportunity.

My first implementation directly transformed expression trees, replacing member accesses by conditional member accesses that return null whenever a is null in a.b.

My second implementation was inspired by a question about the relation between andand and the Maybe monad. I thought it would be a good idea to (re)read some papers about monads and test my understanding by implementing a few, including Maybe Monad. I also thought it would be instructive to implement Maybe monad in terms of andand, and andand in terms of Maybe monad.

I'll discuss the code in detail in my next post. For now, you can download a snapshot. I guess I'll migrate my existing hg repo to googlecode in time for the next post to make browsing easier.

Monday, May 18, 2009

.emacs

; Some people I know have asked about my .emacs. Voila:

(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
)

(setq default-buffer-file-coding-system 'unix)

(setenv "PATH" (concat "c:/cygwin-1.7/bin;" (getenv "PATH")))
(setq exec-path (cons "c:/cygwin-1.7/bin/" exec-path))

(require 'cygwin-mount)
(cygwin-mount-activate)

(add-to-list 'load-path "/cygdrive/c/program-files/emacs-22.3/site-lisp")

(add-to-list 'auto-mode-alist '("\\.cs$" . java-mode))
(add-hook 'java-mode-hook
(lambda ()
(setq indent-tabs-mode nil)))

(autoload 'js2-mode "js2" nil t)
(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
(add-hook 'js2-mode-hook
(lambda ()
(setq indent-tabs-mode nil)))

(autoload 'python-mode "python-mode" "Python Mode." t)
(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))
(add-to-list 'interpreter-mode-alist '("python" . python-mode))
(add-hook 'python-mode-hook
(lambda ()
(set (make-variable-buffer-local 'beginning-of-defun-function)
'py-beginning-of-def-or-class)
(setq outline-regexp "def\\|class ")
(setq indent-tabs-mode nil)))

(load (concat "/cygdrive/c/program-files/emacs-22.3/site-lisp/" "nxml-mode-20041004/rng-auto.el"))
(add-to-list 'auto-mode-alist '("\\.\\(xml\\|xsl\\|rng\\|xhtml\\)\\'" . nxml-mode))
(add-hook 'nxml-mode-hook
(lambda ()
(setq indent-tabs-mode nil)))
(setq magic-mode-alist
(cons '("<\\?xml" . nxml-mode)
magic-mode-alist))

(setq binary-process-input t)
(setq w32-quote-process-args ?\")
(setq shell-file-name "bash") ;; or sh if you rename your bash executable to sh.
(setenv "SHELL" shell-file-name)
;; For subprocesses invoked via the shell
;; (e.g., "shell -c command")
(setq explicit-shell-file-name shell-file-name)
(setq explicit-sh-args '("-login" "-i"))

(put 'erase-buffer 'disabled nil)