一からはじめる Common Lisp で
AtCoder
(VS Code環境構築ガイド)

  • 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の操作もできます
SBCLCommon Lispの処理系。コードを実行する本体
Quicklispライブラリを管理するツール。AliveがREPL連携に使います
AliveVS 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.lispsolve 関数と 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 47
100 200300

解答

(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 4Even
1 21Odd
2 2Even

解答

(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)

01からなる3文字の文字列Sが与えられます。
1の個数を出力してください。

入力形式

S

入出力例

入力出力
1012
0000
1113

解答

(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でつなぐ、という流れが身につくと、より複雑な問題にも同じやり方で挑めます。