はじめに

2015 年は SICP を読んでいく予定です.

というわけで, Scheme の開発環境を Emacs で構築しました.

Scheme の処理系 Gauche

まずは, Scheme 処理系をインストール.(ゴーシュ)

gosh -V

scheme-mode

Default で Emacs にはいっている. 以下の設定を参考にした.

;; UTF-8 に統一
(setq process-coding-system-alist
      (cons '("gosh" utf-8 . utf-8) process-coding-system-alist))

(setq scheme-program-name "gosh -i")
(autoload 'scheme-mode "cmuscheme" "Major mode for Scheme." t)
(autoload 'run-scheme "cmuscheme" "Run an inferior Scheme process." t)

;; 別のウィンドウに gosh を動作させる
(defun scheme-other-window ()
  "Run Gauche on other window"
  (interactive)
  (split-window-horizontally (/ (frame-width) 2))
  (let ((buf-name (buffer-name (current-buffer))))
    (scheme-mode)
    (switch-to-buffer-other-window
     (get-buffer-create "*scheme*"))
    (run-scheme scheme-program-name)
    (switch-to-buffer-other-window
     (get-buffer-create buf-name))))

(define-key global-map "\C-cS" 'scheme-other-window)

smartparens

カッコをあつかうための多機能な移動・編集ツール.

(require 'smartparens-config)
(smartparens-global-mode t)

default

smartparens-config では以下が設定される.

example

設定例.

あまりに多機能すぎて使いこなす自信がないな..

覚えておきたいのは,

  • かっこで囲む xx sp-pair M-(
  • かっこを外す sp-unwrap C-M-s
(define-key sp-keymap (kbd "C-M-f") 'sp-forward-sexp)
(define-key sp-keymap (kbd "C-M-b") 'sp-backward-sexp)

(define-key sp-keymap (kbd "C-M-d") 'sp-down-sexp)
(define-key sp-keymap (kbd "C-M-a") 'sp-backward-down-sexp)
(define-key sp-keymap (kbd "C-S-a") 'sp-beginning-of-sexp)
(define-key sp-keymap (kbd "C-S-d") 'sp-end-of-sexp)

(define-key sp-keymap (kbd "C-M-e") 'sp-up-sexp)
(define-key emacs-lisp-mode-map (kbd ")") 'sp-up-sexp)
(define-key sp-keymap (kbd "C-M-u") 'sp-backward-up-sexp)
(define-key sp-keymap (kbd "C-M-t") 'sp-transpose-sexp)

(define-key sp-keymap (kbd "C-M-n") 'sp-next-sexp)
(define-key sp-keymap (kbd "C-M-p") 'sp-previous-sexp)

(define-key sp-keymap (kbd "C-M-k") 'sp-kill-sexp)
(define-key sp-keymap (kbd "C-M-w") 'sp-copy-sexp)

(define-key sp-keymap (kbd "C-M-s") 'sp-unwrap-sexp)
(define-key sp-keymap (kbd "M-<backspace>") 'sp-backward-unwrap-sexp)

(define-key sp-keymap (kbd "C-<right>") 'sp-forward-slurp-sexp)
(define-key sp-keymap (kbd "C-<left>") 'sp-forward-barf-sexp)
(define-key sp-keymap (kbd "C-M-<left>") 'sp-backward-slurp-sexp)
(define-key sp-keymap (kbd "C-M-<right>") 'sp-backward-barf-sexp)

(define-key sp-keymap (kbd "M-D") 'sp-splice-sexp)
(define-key sp-keymap (kbd "C-M-<delete>") 'sp-splice-sexp-killing-forward)
(define-key sp-keymap (kbd "C-M-<backspace>") 'sp-splice-sexp-killing-backward)
(define-key sp-keymap (kbd "C-S-<backspace>") 'sp-splice-sexp-killing-around)

(define-key sp-keymap (kbd "C-]") 'sp-select-next-thing-exchange)
(define-key sp-keymap (kbd "C-<left_bracket>") 'sp-select-previous-thing)
(define-key sp-keymap (kbd "C-M-]") 'sp-select-next-thing)

(define-key sp-keymap (kbd "M-F") 'sp-forward-symbol)
(define-key sp-keymap (kbd "M-B") 'sp-backward-symbol)

(define-key sp-keymap (kbd "H-t") 'sp-prefix-tag-object)
(define-key sp-keymap (kbd "H-p") 'sp-prefix-pair-object)
(define-key sp-keymap (kbd "H-s c") 'sp-convolute-sexp)
(define-key sp-keymap (kbd "H-s a") 'sp-absorb-sexp)
(define-key sp-keymap (kbd "H-s e") 'sp-emit-sexp)
(define-key sp-keymap (kbd "H-s p") 'sp-add-to-previous-sexp)
(define-key sp-keymap (kbd "H-s n") 'sp-add-to-next-sexp)
(define-key sp-keymap (kbd "H-s j") 'sp-join-sexp)
(define-key sp-keymap (kbd "H-s s") 'sp-split-sexp)

;;;;;;;;;;;;;;;;;;
;; pair management
(sp-local-pair 'minibuffer-inactive-mode "'" nil :actions nil)

;;; lisp modes
(sp-with-modes sp--lisp-modes
  (sp-local-pair "(" nil :bind "C-("))

(sp-pair "(" ")" :wrap "M-(")

rainbow-delimiters

かっこの深さに応じて色付けしてくれる.

かっこの強調をどきつくする. これはいいなぁ.

注意 テーマ読み込みのあとに配置すること.

(require 'rainbow-delimiters)
(add-hook 'emacs-lisp-mode-hook 'rainbow-delimiters-mode)
(add-hook 'scheme-mode-hook 'rainbow-delimiters-mode)
(add-hook 'lisp-mode-hook 'rainbow-delimiters-mode)

;; these setting should be placed after load-theme
;; using stronger colors
(require 'cl-lib)
(require 'color)

;; 関数にしないとうまくいかない...手動で有効に
(defun rainbow-delimiters-using-stronger-colors ()
  (interactive)
  (cl-loop
   for index from 1 to rainbow-delimiters-max-face-count
   do
   (let ((face (intern (format "rainbow-delimiters-depth-%d-face" index))))
     (cl-callf color-saturate-name (face-foreground face) 100))))

;; making unmatched parens stand out more
(set-face-attribute 'rainbow-delimiters-unmatched-face nil
            :foreground 'unspecified
            :inherit 'error
            :strike-through t)

SICP を info で読む

以下の設定で Emacs の info で SICP が読める (English)

この方法のよいところは, テキストの文章をそのまま C-x C-e で評価して実 行できるところ.

# sicp.info 取得
wget https://www.neilvandyke.org/sicp-texi/sicp.info.gz
gunzip sicp.info.gz

# /usr/local/info に sicp.info をコピー.
$ sudo mkdir -p /usr/local/info
$ sudo cp sicp.info /usr/local/info

# dir ファイルを編集.
$ sudo emacs /usr/local/share/info/dir

# 次の二行を追記.
 The Algorithmic Language Scheme
 * SICP : (sicp.info). Structure and Interpretation of Computer Programs.

調べたけど利用しないもの

せっかく調べたけど, 設定を有効にしない (できない) ものも列挙.

paredit

Lisp コードで頻出する括弧類のバランスを維持することを目的としたもの.

smartparens に人気をとられてしまったかわいそうな子.

gosh-mode

scheme-mode の拡張.

scheme-mode を継承しているので, 基本的な操作は変わらないそうだ.

el-get で取得. リボジトリから取得後に make && make install

(require 'gosh-config)

M-x gosh-run で gosh が起動すれば OK.

scheme-mode に比べて情報がすくないのと, すごさがわからないので, ひとまずは scheme-mode を利用することにした.

なれてきたらそのうちもう一度挑戦する.

scheme-complete

auto-complete で補完をすることができる. デフォルト設定で, そこそこの補完候補が出る.

scheme-complete というものもあるそうなので,気休め程度に導入.

本家のサーバ落ちた?? github の mirror より取得.

以下を参考にして, auto-complete の source に scheme-complete の情報源を加える.

メンテされていないのと, auto-complete で何とかなるので削除.

(autoload 'scheme-smart-complete "scheme-complete" nil t)
(autoload 'scheme-get-current-symbol-info "scheme-complete" nil t)

(eval-after-load 'scheme
  '(define-key scheme-mode-map "\e\t" 'scheme-smart-complete))

;; scheme-mode-hook
(defvar ac-source-scheme
  '((candidates
     . (lambda ()
         (require 'scheme-complete)
         (all-completions ac-target (car (scheme-current-env))))))
  "Source for scheme keywords.")

(add-hook 'scheme-mode-hook
          '(lambda ()
             (make-local-variable 'ac-sources)
             (setq ac-sources (append ac-sources '(ac-source-scheme)))))

eldoc

scheme の eldoc は scheme-complete と合わせて利用するらしいが, eldoc error void-function eldoc-current-symbol とでてエラーする.

(require 'eldoc-extension)
(add-hook 'scheme-mode-hook
  (lambda ()
    ;; Gauche の場合, 次の 2 個の変数を設定しておいたほうがよいのかも.
    (setq default-scheme-implementation 'gauche)
    (setq *current-scheme-implementation* 'gauche)
    ;; eldoc-mode
    (set (make-local-variable 'eldoc-documentation-function)
     'scheme-get-current-symbol-info)
    (eldoc-mode t)
    )
  )
(setq lisp-indent-function 'scheme-smart-indent-function)

flymake 設定

glint というものがあるらしい. gauche 0.8.13 でしか動作しないようなので試していない.