- Common LispでAtCoderに取り組むため、SBCL・Quicklisp・VS Code・Aliveの4つを使った開発環境をWindowsに構築します。
- VS CodeのターミナルからSBCLとQuicklispをインストールし、Alive拡張でエディタとREPLを連携させます。
- solve関数に解法を、main関数に入出力を分けて書くことで、REPLで動作を確認しながら開発できます。
- 環境が整ったらABCのA問題から始め、REPLで小さく試しながらコードを仕上げてAtCoderに貼り付けて提出します。
1. Common Lispの開発環境をVS Codeで作る
プログラミングの問題解きをCommon Lispで始めるための環境をWindows上に作ります。
たとえば、AtCoderはコードをテキストで入力欄に貼り付けて提出します。
ここでは、「書いて試す」専用の環境を作ります。
使うのは、SBCL、Quicklisp、VS Code、Alive拡張の4つです。
| ツール | 役割 |
|---|---|
| VS Code | コードを書くエディタ。ターミナルからSBCLの操作もできます |
| SBCL | Common Lispの処理系。コードを実行する本体 |
| Quicklisp | ライブラリを管理するツール。AliveがREPL連携に使います |
| Alive | VS Code上でSBCLのREPLと連携する拡張機能 |
QuicklispはSBCLのREPL上で動かし、AliveはQuicklispで入れたライブラリを使います。
1.1. Step 1. VS Codeをインストールする
Visual Studio Code公式サイトからWindows版をダウンロードしてインストールします。
設定は、デフォルト(既定)のままで大丈夫です。
インストールが終わったらVS Codeを起動し、作業フォルダを作ります。
まず、メニューから「ターミナル → 新しいターミナル」を開きます。
そして、次のコマンドを実行します。
mkdir C:\atcoder\lisp
cd C:\atcoder\lispCode language: PowerShell (powershell)
以降のStep 2とStep 3の作業は、このVS Codeのターミナルから行います。
1.2. Step 2. SBCLをインストールする
SBCLはSteel Bank Common Lispの略で、Common Lispの代表的な処理系です。
SBCL公式サイトからWindows版インストーラをダウンロードしてください。sbcl-x.x.x-x86-64-windows-binary.msiのようなファイルです。
ダウンロードしたら実行し、デフォルト設定のままインストールします。
インストール後、VS Codeのターミナルで動作確認します。
sbcl --versionCode language: PowerShell (powershell)
バージョン番号が表示されれば成功です。
表示されない場合は、VS Codeを再起動してターミナルを開き直してください。
それでも表示されない場合は、SBCLのインストール先(C:\Program Files\Steel Bank Common Lisp\など)をWindowsの環境変数Pathに追加してください。
1.3. Step 3. Quicklispをインストールする
Quicklispは、Common Lispのライブラリを管理するツールです。
AliveがREPL連携に内部で使うため、SBCLの次に入れます。
ブラウザでhttps://beta.quicklisp.org/quicklisp.lispを開き、quicklisp.lispをダウンロードします。
ここではC:\Users\ユーザー名\Downloads\quicklisp.lispに保存されたとします。
VS Codeのターミナルで次を実行します。
sbcl --load C:\Users\ユーザー名\Downloads\quicklisp.lispCode language: PowerShell (powershell)
SBCLのREPLが起動し、*プロンプトが表示されたら次を入力します。
REPLはRead-Eval-Print Loopの略で、入力した式を評価して結果を返す対話環境です。
(quicklisp-quickstart:install)Code language: Lisp (lisp)
インストールが終わったら続けて実行します。
(ql:add-to-init-file)Code language: Lisp (lisp)
これでSBCL起動時にQuicklispが自動的に読み込まれるようになります。
最後に終了します。
(quit)Code language: Lisp (lisp)
1.4. Step 4. Alive拡張をインストールする
Aliveは、VS Code上でCommon LispのREPLと連携するための拡張機能です。
エディタ上のコードをREPLに送って試せるようになります。
VS Codeの左側の拡張機能アイコンをクリックします。
検索欄にAliveと入力し、「Alive – The Average Lisp VSCode Environment」をインストールしてください。
インストール後、VS Codeを再起動します。
1.5. VS Codeのシンプルな設定
- 拡張機能の追加:日本語の言語パック
- 設定:ホバー(hover)、コードレンズ(code lens)をオフ、オートインデントをオン(format on type)
2. VS CodeにLispを書く
VS CodeでC:\atcoder\lispフォルダを開き、新しいファイルmain.lispを作って次の内容を入力します。
(defun solve (a b)
(+ a b))Code language: Lisp (lisp)
コマンドパレット(Ctrl + Shift + P)を開いてAlive: Start REPL And Attachを実行します。
画面下部にREPLが起動したら接続成功です。
main.lispを開いた状態でAlt + Shift + Lを押します。
REPLで次のように試してみましょう。
(solve 3 4)
; => 7Code language: Lisp (lisp)
7が返れば環境の完成です。
2.1. 日々の開発サイクル
プログラミングの問題を解くときの流れはこうなります。
1. main.lisp に solve 関数と main 関数を書く
2. Alt + Shift + L でファイルをREPLへロード
3. REPLで (solve ...) を試す
4. 直したらまた Alt + Shift + L で再ロード
5. AtCoderサイト の入力欄にコードを貼り付けて提出Code language: CSS (css)
2.2. Lispファイルの基本構成
プログラムでの書き方は、solveに解き方を書き、mainは入力と出力だけ担当する形にすることです。
そうするとREPLでも試しやすくなります。
(defun solve (a b)
(+ a b))Code language: Lisp (lisp)
回答中には、REPLで動作を確認します。
(solve 3 4) ; => 7
(solve 10 20) ; => 30Code language: Lisp (lisp)
2.3. サンプル入力全体を試したいとき
input.txtに入力を書いて渡すこともできます。
(defun main ()
(let ((a (read))
(b (read)))
(princ (solve a b))))
(main)Code language: Lisp (lisp)
readは標準入力から値をひとつ読みます。
スペース区切りで2つ並んでいても、readを2回呼べば順に読めます。
結果は、princで数値や文字列、文字をそのまま出力できます。
より複雑な結果を出力したいときには、format関数もあります。
VS Codeのターミナルで次を実行します。
sbcl --script main.lisp < input.txtCode language: PowerShell (powershell)
REPLに読み込むときは、(main)は、コメントアウトして、提出時だけ有効にします。
;;(main)Code language: Lisp (lisp)
2.4. AtCoderへの提出
提出時は、言語選択で「Common Lisp (SBCL 2.5.8)」を選んで、コードをそのまま貼り付けます。
(defun solve (a b)
(+ a b))
(defun main ()
(let ((a (read))
(b (read)))
(princ (solve a b))))
(main)Code language: Lisp (lisp)
3. かんたんな練習問題
練習問題は、ABC(AtCoder Beginner Contest)のA問題から始めるのがおすすめです。
A問題は、特に基本的なプログラミングの機能を1から練習できます。
最初から解けなくても大丈夫です。
まずはREPLで小さく試しながら考えることが、そのまま練習になります。
3.1. 問題 1. 2数の和
整数AとBが与えられます。
A+Bを出力してください。
入力形式
A B
入出力例
| 入力 | 出力 |
|---|---|
3 4 | 7 |
100 200 | 300 |
解答
(defun solve (a b)
(+ a b))
(defun main ()
(let ((a (read))
(b (read)))
(princ (solve a b))))
(main)Code language: Lisp (lisp)
3.2. 問題 2. 積の奇偶判定(ABC086A – Product)
整数AとBが与えられます。
A×Bが奇数ならOdd、偶数ならEvenを出力してください。
入力形式
A B
入出力例
| 入力 | 出力 |
|---|---|
3 4 | Even |
1 21 | Odd |
2 2 | Even |
解答
(defun solve (a b)
(if (oddp (* a b)) "Odd" "Even"))
(defun main ()
(let ((a (read))
(b (read)))
(princ (solve a b))))
(main)Code language: Lisp (lisp)
oddpはCommon Lispの組み込み関数で、整数が奇数ならTを返します。ifは(if 条件 真のとき 偽のとき)の形で書きます。
このような組み込み関数は、一つずつ使いながら覚えていきます。
REPLで確認するとこうなります。
(oddp (* 3 4)) ; => NIL(偶数)
(oddp (* 1 21)) ; => T(奇数)
(solve 3 4) ; => "Even"
(solve 1 21) ; => "Odd"Code language: Lisp (lisp)
3.3. 問題 3. ビー玉の配置(ABC081A – Placing Marbles)
0と1からなる3文字の文字列Sが与えられます。1の個数を出力してください。
入力形式
S
入出力例
| 入力 | 出力 |
|---|---|
101 | 2 |
000 | 0 |
111 | 3 |
解答
(defun solve (s)
(count #\1 s))
(defun main ()
(let ((s (read-line)))
(princ (solve s))))
(main)Code language: Lisp (lisp)
文字列を読む場合はreadではなくread-lineで1行まとめて受け取ります。countは文字列の中から指定した文字を数える関数です。#\1はCommon Lispの文字リテラルの書き方で、#\aなら文字aを指します。
REPLでの確認はこうなります。
(count #\1 "101") ; => 2
(count #\1 "000") ; => 0
(solve "101") ; => 2Code language: Lisp (lisp)
4. 次のステップ
AtCoder Beginners Selectionにはこのレベルの問題が10問まとまっています。
環境に慣れてきたら、そちらも解いてみてください。
REPLで試す、solveで整理する、mainでつなぐ、という流れが身につくと、より複雑な問題にも同じやり方で挑めます。