#+title: Programming in Scheme for SICP #+author: Howard X. Abrams #+date: 2022-03-01 #+tags: emacs scheme programming lisp A literate programming file configuring Emacs. #+begin_src emacs-lisp :exports none ;;; ha-programming-scheme --- Configuration for Scheme. -*- lexical-binding: t; -*- ;; ;; © 2022-2023 Howard X. Abrams ;; Licensed under a Creative Commons Attribution 4.0 International License. ;; See http://creativecommons.org/licenses/by/4.0/ ;; ;; Author: Howard X. Abrams ;; Maintainer: Howard X. Abrams ;; Created: March 1, 2022 ;; ;; This file is not part of GNU Emacs. ;; ;; *NB:* Do not edit this file. Instead, edit the original literate file at: ;; ~/src/hamacs/ha-programming-scheme.org ;; And tangle the file to recreate this one. ;; ;;; Code: #+end_src * Introduction First, install MIT-Scheme, the Lisp dialect used throughout the SICP book: =brew install mit-scheme= or =sudo apt install mit-scheme= . #+begin_src sh brew install mit-scheme #+end_src Or better yet, let’s use Guile: #+begin_src sh brew install guile #+end_src * Geiser (Scheme Interface) The [[https://www.nongnu.org/geiser/][geiser project]] attempts to be the interface between Emacs and all the Schemes in the world. Since I can’t decide which to use, I’ll install/configure them all. #+begin_src emacs-lisp (use-package geiser :init (setq geiser-mit-binary "/usr/local/bin/scheme" geiser-racket-binary "/usr/local/bin/racket" geiser-guile-binary "/usr/local/bin/guile" geiser-active-implementations '(guile mit) geiser-default-implementations '(guile)) :config (use-package geiser-mit) (use-package geiser-guile) (use-package geiser-racket)) #+end_src ** Org Mode :PROPERTIES: :header-args:scheme: :session *scheming* :results value replace :END: Do we need a Scheme work for Org Babel? According to [[https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-scheme.html][this document]], we just need to make sure we add the =:session= variable to start the REPL. #+begin_src emacs-lisp (use-package ob-scheme :straight (:type built-in) :config (add-to-list 'org-babel-load-languages '(scheme . t))) #+end_src Since the version of Scheme hasn't been updated with the deprecation, and subsequent removal of =org-babel-get-header=, we include it here: #+begin_src emacs-lisp (defun org-babel-get-header (params key &optional others) (delq nil (mapcar (lambda (p) (when (funcall (if others #'not #'identity) (eq (car p) key)) p)) params))) #+end_src Let’s test it out by defining a variable: #+begin_src scheme (define a 42) #+end_src And simply using it: #+begin_src scheme :var b=8 (+ a b) #+end_src #+results: : ;Value: 50 And what about Scheme-specific stuff needed for SICP? #+begin_src scheme (inc 42) #+end_src ** Install SICP :PROPERTIES: :header-args:scheme: :session sicp :results value replace :END: Let’s get the book available as an Info page: #+begin_src emacs-lisp (use-package sicp) #+end_src Still having difficulty getting the Scheme REPL to output the results back into this document. Let’s try Racket... Normally, I would just [[info:SICP][read the book]], however, if we want to read the [[file:~/.emacs.d/straight/build/sicp/sicp.info][sicp.info]] file, we need this, at least, temporarily: #+begin_src emacs-lisp (add-to-list 'auto-mode-alist '("\\.info\\'" . Info-mode)) #+end_src * Racket Actually, let’s do this with [[https://racket-lang.org/][Racket]]: #+begin_src sh brew install racket #+end_src While Racket, as a Scheme, should work with Geiser (below), let’s also get [[https://racket-mode.com/][racket-mode]] working: #+begin_src emacs-lisp (use-package racket-mode :config (setq racket-program "/usr/local/bin/racket")) #+end_src Can we get Racket working with Org? #+begin_src emacs-lisp (use-package ob-racket :straight (:host github :repo "DEADB17/ob-racket") :after org :config (add-to-list 'org-babel-load-languages '(racket . t))) #+end_src ** Try It Out :PROPERTIES: :HEADER-ARGS:racket: :session racketeering :results value replace :lang racket :END: Working for values? #+begin_src racket (* 6 7) #+end_src #+results: : 42 Working for output? #+begin_src racket :results output replace (define str-1 "hello") (define str-2 "world") (define all (string-join (list str-1 str-2) ", ")) (display (string-titlecase all)) #+end_src #+results: : Hello, World The interface is horrendously slow, as the =:session= doesn’t seem to work, and starting up a Racket REPL takes a long time. ** SICP and Racket :PROPERTIES: :header-args:racket: :session *rsicp* :results value replace :lang sicp :END: If using [[https://docs.racket-lang.org/sicp-manual/SICP_Language.html][Racket for SICP]], install the SICP language: #+begin_src sh raco pkg install --auto --update-deps sicp #+end_src We now can give it a =#lang sicp= (or better yet, use the =:lang= header) to define certain SICP-specify features: Let’s try this now: #+begin_src racket (inc 42) #+end_src #+results: : 43 * Technical Artifacts :noexport: Let's =provide= a name so we can =require= this file: #+begin_src emacs-lisp :exports none (provide 'ha-programming-scheme) ;;; ha-programming-scheme.el ends here #+end_src #+description: A literate programming file configuring Emacs. #+property: header-args:sh :tangle no #+property: header-args:emacs-lisp :tangle yes #+property: header-args :results none :eval no-export :comments no mkdirp yes #+options: num:nil toc:t todo:nil tasks:nil tags:nil date:nil #+options: skip:nil author:nil email:nil creator:nil timestamp:nil #+infojs_opt: view:nil toc:t ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js