HaskellでAtCoderを楽しむためのstack-template(2025-10-14改訂版)
はじめに
この記事は、AtCoderをHaskellで楽しむために筆者が作成したstackのテンプレートの使い方を説明します。さらに、このテンプレートもとに、カスタマイズしやすいように、筆者のテンプレートファイルatcoder.hsfiles
の概要を解説します。
AtCoder 言語アップデート 2025 に対応できるように設定しますが、検証が不十分である点はご理解ください。
おことわり
この記事を、読んで、あるいは、読まずに、おこなわれた全ての行為について、筆者は一切の責任を負いません。筆者の手順、テンプレートの利用は、自己責任でおこなって下さい。
前提となるPC環境
デバイス基本仕様
項目 | 内容 |
---|---|
CPU | 12th Gen Intel(R) Core(TM) i9-12900H |
GPU | NVIDIA RTX A2000 8GB |
RAM | 64GB |
OS | Pop!_OS 24.04 LTS Beta |
Pop!_OS 24.04 LTS Beta は Ubuntu 24.04 LTS をベースにした Linux ディストリビューション
前提PC環境とその構築概要
開発用基本パッケージ
Haskellの言語処理系GHCの前提となる基本パッケージのインストール
sudo apt install build-essential libffi-dev libgmp-dev libncurses-dev
sudo apt install libgsl-dev liblapack-dev libatlas-base-dev
Haskell処理系
- GHCup 0.1.50.2
- Stack 3.7.1
- HLS 2.10.0.0
- cabal 3.16.0.0
- GHC 9.8.4
GHCupのサイトからダウンロード、セットアップ
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
とすると、
Welcome to Haskell!
This script can download and install the following binaries:
* ghcup - The Haskell toolchain installer
* ghc - The Glasgow Haskell Compiler
* cabal - The Cabal build tool for managing Haskell software
* stack - A cross-platform program for developing Haskell projects (similar to cabal)
* hls - (optional) A language server for developers to integrate with their editor/IDE
ghcup installs only into the following directory,
which can be removed anytime:
/home/nobsun/.ghcup
Press ENTER to proceed or ctrl-c to abort.
Note that this script can be re-run at any given time.
ここで ENTERキーを押す。
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 29.6M 100 29.6M 0 0 15.4M 0 0:00:01 0:00:01 --:--:-- 15.4M
[ Info ] downloading: https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-0.0.9.yaml as file /home/nobsun/.ghcup/cache/ghcup-0.0.9.yaml
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 560k 100 560k 0 0 6831k 0 --:--:-- --:--:-- --:--:-- 6916k
[ Info ] Upgrading GHCup...
[ Warn ] No GHCup update available
System requirements
Note: You need the following packages: curl g++ gcc gmp make ncurses realpath xz-utils pkg-config. Consult your distro documentation on the exact names of those packages.
Press ENTER to proceed or ctrl-c to abort.
ここも、ENTERキーを押します。
-------------------------------------------------------------------------------
GHCup provides different binary distribution "channels". These are collections of tools
and may differ in purpose and philosophy. First, we select the base channel.
[S] Skip [D] Default (GHCup maintained) [V] Vanilla (Upstream maintained) [?] Help (default is "Skip").
ここは、デフォルトで Skip、単にENTERキーを押します。
-------------------------------------------------------------------------------
Detected bash shell on your system...
Do you want ghcup to automatically add the required PATH variable to "/home/nobsun/.bashrc"?
[P] Yes, prepend [A] Yes, append [N] No [?] Help (default is "P").
パス設定を~/.bashrc
に追加。
これも、デフォルトで prepend、単にENTERキーを押します。
-------------------------------------------------------------------------------
Do you want to install haskell-language-server (HLS)?
HLS is a language-server that provides IDE-like functionality
and can integrate with different editors, such as Vim, Emacs, VS Code, Atom, ...
Also see https://haskell-language-server.readthedocs.io/en/stable/
[Y] Yes [N] No [?] Help (default is "N").
Y
HLS とエディタを連携させるか。筆者は VS Code を使っているので Y を入力します。
-------------------------------------------------------------------------------
Do you want to enable better integration of stack with GHCup?
This means that stack won't install its own GHC versions, but uses GHCup's.
For more information see:
https://docs.haskellstack.org/en/stable/configure/customisation_scripts/#ghc-installation-customisation
If you want to keep stacks vanilla behavior, answer 'No'.
[Y] Yes [N] No [?] Help (default is "Y").
stack と GHCup を連携するか。デフォルトの Yes、単に ENTERキーを押します。
あとは、最後まで待ちます。少し時間がかかる場合があります。
[ Info ] downloading: https://downloads.haskell.org/ghcup/unofficial-bindists/ghc/9.6.7/ghc-9.6.7-x86_64-rocky8-linux.tar.xz as file /home/nobsun/.ghcup/cache/ghc-9.6.7-x86_64-rocky8-linux.tar.xz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 192M 100 192M 0 0 26.4M 0 0:00:07 0:00:07 --:--:-- 28.1M
[ Info ] verifying digest of: ghc-9.6.7-x86_64-rocky8-linux.tar.xz
[ Info ] Unpacking: ghc-9.6.7-x86_64-rocky8-linux.tar.xz to /home/nobsun/.ghcup/tmp/ghcup-7c47c5fdf6996df2
[ Info ] Installing GHC (this may take a while)
[ ghc-make ] fi
[ ghc-make ] Copying docs to /home/nobsun/.ghcup/tmp/ghcup-bdeec55a8c07d3c0/home/nobsun/.ghcup/ghc/9.6.7/share/doc/ghc-9.6.7
[ ghc-make ] /usr/bin/install -c -m 755 -d "/home/nobsun/.ghcup/tmp/ghcup-bdeec55a8c07d3c0/home/nobsun/.ghcup/ghc/9.6.7/share/doc/ghc-9.6.7"
[ ghc-make ] if [ -d doc ]; then \
[ ghc-make ] cd doc; /usr/bin/find . -type f -exec sh -c \
[ ghc-make ] '/usr/bin/install -c -m 755 -d "/home/nobsun/.ghcup/tmp/ghcup-bdeec55a8c07d3c0/home/nobsun/.ghcup/ghc/9.6.7/share/doc/ghc-9.6.7/`dirname $1`" && /usr/bin/install -c -m 644 "$1" "/home/nobsun/.ghcup/tmp/ghcup..[ Info ] Merging file tree from "/home/nobsun/.ghcup/tmp/ghcup-bdeec55a8c07d3c0/home/nobsun/.ghcup/ghc/9.6.7" to "/home/nobsun/.ghcup/ghc/9.6.7"
[ Info ] GHC installation successful
[ Info ] HLS is not supported for 9.6.7 yet. To build from source, run:
[ ... ] ghcup compile hls -g 2.9.0.1 --ghc 9.6.7 --cabal-update -- --constraint="ghc-lib-parser == 9.8.5.20250214" --index-state="2025-02-14T12:50:38Z"
[ Info ] GHC 9.6.7 successfully set as default version
[ Info ] downloading: https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/3.12.1.0/cabal-install-3.12.1.0-x86_64-linux-centos7.tar.xz as file /home/nobsun/.ghcup/cache/cabal-install-3.12.1.0-x86_64-linux-centos7.tar.xz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 6962k 100 6962k 0 0 9521k 0 --:--:-- --:--:-- --:--:-- 9511k
[ Info ] verifying digest of: cabal-install-3.12.1.0-x86_64-linux-centos7.tar.xz
[ Info ] Unpacking: cabal-install-3.12.1.0-x86_64-linux-centos7.tar.xz to /home/nobsun/.ghcup/tmp/ghcup-5ff794354b9df118
[ Info ] Installing cabal
[ Info ] Cabal installation successful
Downloading the latest package list from hackage.haskell.org
Package list of hackage.haskell.org has been updated.
The index-state is set to 2025-10-13T08:48:23Z.
To revert to previous state run:
cabal v2-update 'hackage.haskell.org,2025-10-08T23:27:01Z'
[ Info ] downloading: https://downloads.haskell.org/~ghcup/unofficial-bindists/haskell-language-server/2.10.0.0/haskell-language-server-2.10.0.0-x86_64-linux-rocky8.tar.xz as file /home/nobsun/.ghcup/cache/haskell-language-server-2.10.0.0-x86_64-linux-rocky8.tar.xz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 196M 100 196M 0 0 25.1M 0 0:00:07 0:00:07 --:--:-- 26.1M
[ Info ] verifying digest of: haskell-language-server-2.10.0.0-x86_64-linux-rocky8.tar.xz
[ Info ] Unpacking: haskell-language-server-2.10.0.0-x86_64-linux-rocky8.tar.xz to /home/nobsun/.ghcup/tmp/ghcup-0b7f1847d479e5c8
[ Info ] Installing HLS
[ Info ] Merging file tree from "/home/nobsun/.ghcup/tmp/ghcup-e004da959664b2f5/home/nobsun/.ghcup/hls/2.10.0.0" to "/home/nobsun/.ghcup/hls/2.10.0.0"
[ Info ] HLS installation successful
[ Info ] This is just the server part of your LSP configuration. Consult the README on how to
[ ... ] configure HLS, your project and your LSP client in your editor:
[ ... ] https://haskell-language-server.readthedocs.io/en/stable/
[ Info ] downloading: https://downloads.haskell.org/~ghcup/unofficial-bindists/stack/3.3.1/stack-3.3.1-linux-x86_64.tar.gz as file /home/nobsun/.ghcup/cache/stack-3.3.1-linux-x86_64.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 21.3M 100 21.3M 0 0 24.4M 0 --:--:-- --:--:-- --:--:-- 24.4M
[ Info ] verifying digest of: stack-3.3.1-linux-x86_64.tar.gz
[ Info ] Unpacking: stack-3.3.1-linux-x86_64.tar.gz to /home/nobsun/.ghcup/tmp/ghcup-932f0c9061d820f1
[ Info ] Installing stack
[ Info ] Stack installation successful
[ Info ] Stack manages GHC versions internally by default. To improve integration, please visit:
[ ... ] https://www.haskell.org/ghcup/guide/#stack-integration
[ ... ]
[ ... ] Also check out:
[ ... ] https://docs.haskellstack.org/en/stable/yaml_configuration
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 766 100 766 0 0 1319 0 --:--:-- --:--:-- --:--:-- 1318
===============================================================================
OK! /home/nobsun/.bashrc has been modified. Restart your terminal for the changes to take effect,
or type ". /home/nobsun/.ghcup/env" to apply them in your current terminal session.
===============================================================================
All done!
To start a simple repl, run:
ghci
To start a new haskell project in the current directory, run:
cabal init --interactive
To install other GHC versions and tools, run:
ghcup tui
If you are new to Haskell, check out https://www.haskell.org/ghcup/steps/
これで端末を再起動すれば、設定が有効になる。
処理系のバージョン調整
GHCup を使って、
- Stack および Cabal の最新バージョンをインストールし、デフォルトに設定
- ghc 9.8.4 をインストールし、デフォルトに設定
します。
ghcup tui
矢印キー ↑ ↓ を使って選択、i キーを押すとインストールされる。その後、もういちど選択して、 s キーを押すとデフォルトに設定される。
AtCoder ツール
以下の
- online-judge-tool
- atcoder-cli
- aclogin
online-judge-tool および atcoder-cli については以下の記事を参考にインストール、設定してください。
現時点では、上の2つのツールだけでは、AtCoder へのログインに失敗します。以下のツールでセッションcoockieを保存するなどが必要です。
AtCoder用 stack-template の使い方
stack-templates リポジトリのフォーク
ここで紹介するテンプレートは、十分にテストされたものとはいえないのと、筆者の個人的嗜好が強い設定になっているので、自分用に修正、カスタマイズしたくなるところが多いでしょう。とくに、各ライブラリパッケージのバージョン調整、GHCのオプションや言語拡張プラグマ、および、雛形となるMain.hs
などは自分用にカスタマイズすることをお勧めします。
カスタマイズいろいろ試すには、
を自分のGitHubアカウントにフォークしてください。カスタマイズするファイルは、atcoder.hsfiles
です。
自分のカスタムatcoder.hsfiles
を試すには、たとえば、
stack new abc426 <GitHubユーザー名>/atcoder
としてください。手元にAtCoderのプロジェクトabc426
ディレクトリが新規に作成できます。
プロジェクトの流れ
例として、ABC 426 用のプロジェクトを作ります。
あらかじめ、
acc login
で、AtCoder
へログインを確認しておきます。ログイン済の場合は「プロジェクトの初期化」にすすんでください。そうでない場合は、acc はログインを試みますが、失敗しますので、aclogin
でログインしてください。
aclogin
プロジェクトの初期化
stack new abc426 nobsun/atcoder ## `nobsun`の代りにフォーク先のGitHubユーザー名を使ってください
cd abc426
source activate ## ユーティリティスクリプトの実行権限 ON
./building ## ライブラリパッケージの準備
次の initializing スクリプトは、当該コンテストのテスト用サンプルケースを取得しようとします。公開前のコンテストからは取ってこれませんので、initializing スクリプトは必ずAtCoderの当該コンテストが公開後(コンテストが開始後)に起動してください。
./initializing ## プロジェクトディレクトリの(再)構成、テスト用サンプルデータの取得
注意
initializing
スクリプトは内部でsetting
スクリプトを呼んでいます。setting
スクリプトは、implicit-hie
パッケージが提供するgen-hie
コマンドを使います。gen-hie
がローカル環境にない場合は、implicit-hie
パッケージを無断でインストールし、gen-hie
コマンドを$HOME/.local/bin/
に設置します。
問題 A を「現在の問題」に設定する
./resetting a
問題 A の解答プログラムを作成する
競技者は、app/a/Main.hs
を編集して、問題 A の解答プログラムを作成してください。
問題 A の解答プログラムのビルドとサンプルデータによるテスト
./checking
問題 A の解答プログラムを提出 -- (未確認)
コンテスト開催時間中のみ以下コマンドで提出可能ならいいなぁ。
./submitting
提出できないときは、Web上で提出してください。
stack のテンプレートファイル
テンプレートファイルは、.hsfiles
という拡張子をもつテキストファイルです。筆者はatcoder.hsfiles
というファイルにしています。テンプレートは、stack new
のときに、プロジェクトのルートディレクトリ以下に配置するファイルを指定するものです。
カスタムしたテンプレートは、GitHub にstack-templates
というリポジトリを作成してその中に置くと、ローカルマシンで、stack new
で指定できようになります。複数あれば、状況に応じて使い分けられます。
たとえば、この記事のテンプレートは、https://github.com/nobsun/stack-templates/atcoder.hsfiles
なので、これをそのまま使って、ABC 426を楽しむには、
stack new abc426 nobsun/atcoder
とします。
プロジェクトディレクトリの初期構成
stack new abc426 nobsun/atcoder
を実行直後のプロジェクトディレクトリの構成は以下のようになります。
$ tree -a abc426
abc426
├── .ghci
├── .gitignore
├── ChangeLog.md
├── LICENSE
├── README.md
├── Setup.hs
├── abc426.cabal
├── activate
├── app
│ ├── Main.hs
│ └── zzz
│ └── add-entry
│ └── Main.hs
├── building
├── checking
├── executing
├── ghcing
├── initializing
├── package.yaml
├── resetting
├── setting
├── stack.yaml
└── submitting
4 directories, 20 files
これらのファイルのうち、abc426.cabal
およびstack.yaml
以外のファイルは、atcoder.hsfiles
で指定します。abc426.cabal
は、stackがpackage.yaml
をもとに生成してくれますので特にさわる必要はありません。stack.yaml
は、stackがデフォルトで設定したものを、ユーティリティスクリプトintializing
が書き換えます。
atcoder.hsfiles の構成
テンプレートファイル *.hsfiles
は、複数のセクションから構成されて、個々のセクションはフラットに順不同でならべる。また、個々のセクションは、stack new
コマンドでプロジェクトディレクトリに初期配置する個々のファイルに対応します。
個々のセクションは、START_FILE
プラグマ指定行、すなわち、{-# START_FILE 《ファイルパス》 #-}
のみからなる行から、次のSTART_FILE
プラグマ指定行またはファイル終端の直前行までになります。
.ghci
テンプレートのapp/Main.hs
における言語拡張プラグマと同じものをghci
でも有効にしています。ユーティリティスクリプトghcing
で必要になる。
{-# START_FILE .ghci #-}
:set -XCPP
:set -XGHC2021 -XLambdaCase -XMultiWayIf -XNPlusKPatterns -XOverloadedStrings -XLexicalNegation
:set -XDataKinds -XPolyKinds -XNoStarIsType -XTypeFamilyDependencies -XUndecidableInstances
.gitignore
プロジェクトをgit
で管理する場合に必要になります。stack
を使うことを前提としているので、.cabal
ファイルは管理外にしてあります。
{{name}}
の部分は、stack new
コマンド実行の際に、渡されたプロジェクト名に置換されます。
{-# START_FILE .gitignore #-}
.stack-work/
dist-new/
{{name}}.cabal
*.log
.curname
core
*.hi
*.o
*~
ChangeLog.md
{-# START_FILE ChangeLog.md #-}
# ChangeLog for {{name}}
## Unreleased changes
LICENSE
BSD-3
の使用許諾書ファイル。{{copyright}}
および{{author-name}}
の部分は、stack
の設定ファイル、デフォルトでは$HOME/.stack/config.yaml
で設定されている、それぞれcopyright
およびauthor-name
の値で置換されます。
{-# START_FILE LICENSE #-}
Copyright {{copyright}}
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of {{author-name}}{{^author-name}}Author name here{{/author-na
me}} nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
README.md
{-# START_FILE README.md #-}
# {{name}}
Setup.hs
{-# START_FILE Setup.hs #-}
import Distribution.Simple
main = defaultMain
activate
もろもろのツール群をアクティベート
- ユーティリティスクリプトを実行フラッグON
-
stack.yaml
書き換え - 利用パッケージ設定(初回は少々時間がかかります)
{-# START_FILE activate #-}
# 実行ビットON
chmod u+x building checking executing ghcing initializing resetting setting submitting
# stack.yaml 書き換え
tee stack.yaml > /dev/null << 'EOF'
snapshot: lts-23.28
packages:
- .
EOF
# 利用パッケージ調整
stack build
initializing
プロジェクトの初期化を行います。
- 雛形
Main.hs
を atcoder-cli に設定 - atcoder-cli の設定
- atcoder-cli によるプロジェクト初期化(問題毎のディレクトリ生成、サンプルケースの取得、設置
- stack 用にプロジェクト再編成
{-# START_FILE initializing #-}
#!/bin/bash
# 雛形`Main.hs`を atcoder-cli に設定
cp app/Main.hs ~/.config/atcoder-cli-nodejs/haskell/
# atcoder-cli の設定
acc config default-task-choice all
acc config default-template haskell
# atcoder-cli によるプロジェクト初期化
acc new {{name}}
# stack 用にプロジェクト再編成
mv {{name}}/contest.acc.json ./
jq -r '.tasks[].id' ./contest.acc.json | while read tid; do
mv {{name}}/${tid: -1} app/
./setting ${tid: -1}
done
rmdir {{name}}
cp contest.acc.json app/
ln -s ./app ./abc426
./resetting a
setting
指定した問題ID(通常、a
からg
までのどれか)用のサブプロジェクトディレクトリをapp/
以下に初期化します。
{-# START_FILE setting #-}
#!/bin/bash
# 指定した問題用のエントリーを package.yaml に追加
stack exec -- add-entry $1
# 現在の問題を設定する
echo "export CURRENT_STACK_EXE_ENTRY=$1" > .curname
# 現在の問題用 Main.hs を仮ビルド
stack build {{name}}:exe:$1
# hie.yaml の更新
if type "gen-hie" > /dev/null 2>&1; then
gen-hie > hie.yaml
else
stack install implicit-hie
gen-hie > hie.yaml
fi
resetting
「現在の問題」を指定した問題IDに再設定します。
{-# START_FILE resetting #-}
#!/bin/bash
echo "export CURRENT_STACK_EXE_ENTRY=$1" > .curname
checking
「現在の問題」に対応する解答プログラムをチェックします。
- 解答プログラムのコンパイル
- サンプル入力ごとに解答プログラムの実行し、出力をサンプル出力と比較
{-# START_FILE checking #-}
#!/bin/bash
source .curname
# 解答プログラムのコンパイル
./building
# 解答プログラムのテスト
oj t -c ./executing -d app/$CURRENT_STACK_EXE_ENTRY/tests
building
「現在の問題」に対応する解答プログラムをコンパイルする
{-# START_FILE building #-}
#!/bin/bash
source .curname
stack build {{name}}:exe:$CURRENT_STACK_EXE_ENTRY
executing
「現在の問題」に対応する解答プログラムを起動します。
{-# START_FILE executing #-}
#!/bin/bash
source .curname
stack exec -- $CURRENT_STACK_EXE_ENTRY
submitting
「現在の問題」に対応する解答プログラムを提出します。
{-# START_FILE submitting #-}
#!/bin/bash
source .curname
cd {{name}}/$CURRENT_STACK_EXE_ENTRY && acc s -s -- --no-open
ghcing
「現在の問題」に対する解答プログラムを GHCi にロードします。これは個別の関数の動作確認のために使用できます。
{-# START_FILE ghcing #-}
#!/bin/bash
source .curname
stack exec -- ghci app/$CURRENT_STACK_EXE_ENTRY/Main.hs
package.yaml
設定ファイルStack 用のプロジェクト設定ファイル。ビルドの際にこのファイルをもとに、cabalファイルが自動生成されます。
default-extensions
の部分をカスタマイズした場合は、app/Main.hs
の言語拡張プラグマ指定との整合性、および、.ghci
のフラッグ設定との整合性に注意して調整してください。
app/zzz/Main.hs
ユーティリティHaskellスクリプト指定した問題IDに対する解答プログラムのテンプレートを配置し、building
とexecuting
でビルドおよび起動ができるように、package.yaml
にエントリーを追加します。
このスクリプトはバグ修正以外では変更しないでください。
app/Main.hs
解答プログラムのテンプレート 自分用にカスタマイズした解答プログラムの雛形は atcoder-cli の設定時に、$HOME/.config/atcoder-cli-nodejs/haskell/
に置くことを想定しています。
したがって、通常このファイルが使われることはありません。カスタマイズの一例として参考になるかもしれません。
app/Main.hs
の基本的な考え方
このファイルは一例にすぎませんので、完全に独自のものに差し替えてかまいません。完全に独自のものに差し替えるときは、このファイルでの言語拡張プラグマ指定と、package.yaml
ファイルの default-extensions
のリスト、および、.ghci
ファイルでのフラッグ設定とが整合するようにしてください。
main
の定義は以下のとおりです。
main :: IO ()
main = B.interact (detokenize . encode . solve . decode . entokenize)
このパターンは、対話的(interactive)ではない問題にしか対応できません。しかし、AtCoder Beginner Contestでは対話的なプログラムが必要になることはないといってもよさそうです。入出力のパフォーマンスについては十分な考察や実証をおこなっていません。
プログラムの流れは、
-
entokenize :: B.ByteString -> [[I]]
: 標準入力全体を入力トークンのリスト(行)のリストに分解 -
decode :: [[I]] -> Dom
: 入力トークンのリストのリストから、solve
関数の入力データを構成 -
solve :: Dom -> Codom
:Dom
が入力データの型、Codom
が出力(解答)データの型 -
encode :: Codom -> [[O]]
:solve
関数の出力データから、出力トークンのリストのリストを構成 -
detokenize :: [[O]] -> B.ByteString
: 出力トークンのリストのリストをまとめて標準出力に置くデータを構成
競技者は、
- 入力トークンの型
I
をAsToken
型クラスのインスタンスを宣言済みの型(B.ByteString
、String
、Char
、Int
、Integer
、Double
)のうちどれか1つに決定 - 出力トークンの型
O
をAsToken
型クラスのインスタンスを宣言済みの型(B.ByteString
、String
、Char
、Int
、Integer
、Double
)のうちどれか1つに決定 -
solve
関数の入力の型Dom
を決定 -
solve
関数の出力の型Codom
を決定 -
decode :: [[I]] -> Dom
を実装 -
encode :: Codom -> [[O]]
を実装
します。entokenize
とdetokenize
はAsToken
型クラスのメソッドですので、AsToken
型クラスのインスタンスを宣言済みの型に関しては実装する必要はありません。
インポート宣言
使いそうなモジュールをインポート宣言に加えてあります。各自必要に応じてカスタマイズしてください。
ここでインポートできモジュールは、package.yaml
のdependencies
に記述されているパッケージに含まれているものです。
また、
にあるモジュールもインポート可能です。
デバッグプリント
app/Main.hs
37行目 debug = () /= ()
を debug = () == ()
に書き換えると、trace :: String -> a -> a
(127-129行目)およびtracing :: Show a => a -> a
(131-132行目)が機能するようになります。
メッセージ付きエラー例外
app/Main.hs
の135-136行目impossible :: String -> a
、138-139行目invalid :: String -> a
盆栽
自分用の盆栽コードを追加する場合は、
- 盆栽に必要なインポート宣言は、必要に応じて、所定の場所に追加
- 盆栽コード本体は、
{- Bonsai -}
以降に追加
してください。
Discussion