SlideShare a Scribd company logo
Haskell で CLI
@matsubara0507
新しくプログラミング言語を学んだ
ら何をするか?
コマンドを作りますね!
Agenda
1. コマンドライン引数
2. Alt. Prelude: RIO
3. Stack Template
コマンドライン引数
Haskell でコマンドライン引数
他にもたくさんあるけど、例えば
System.Environment.getArgs
System.Console.GetOpt
optparse-applicative
System.Environment.getArgs
base  パッケージにある関数
getLine  や  getEnv  のような他の IO 系と同じように扱
える
-- getArgs :: IO [String]
import System.Environment (getArgs)
main :: IO ()
main = do
args <- getArgs
print $ "Hi, " ++ head args
しかし,ただの空白区切
System.Console.GetOpt
これも  base  にある
getArgs  で得た文字列を特定の型に変換してくれる.
getOpt
:: ArgOrder a -- ^ non-opts な文字列の取り扱い方
-> [OptDescr a] -- ^ opts な文字列の扱い方
-> [String] -- ^ getArgs などで得た文字列
-> ([a], [String], [String])
返り値の型は  (オプションの型, non-opts な文字列, エラー)
(細かい説明は割愛)
System.Console.GetOpt  の使用例
import System.Console.GetOpt
main :: IO ()
main = do
args <- getArgs
let (opts, rest, err) = getOpt Permute options args
print opts
data Flag = Verbose | Version deriving (Show, Eq)
options :: [OptDescr Flag]
options =
[ Option ['v'] ["verbose"] (NoArg Verbose) "..."
, Option ['V'] ["version"] (NoArg Version) "..."
]
optparse-applicative
というパッケージ,よりリッチな事がたくさんできる
stack でも使われている(実質サンプル置き場)
少し使い方が難しいので,簡単にしたラッパーライブ
ラリがたくさんある
optparse­applicative­simple
optparse­generic
optparse­helper
optparse­simple
optparse-applicative  の使用例
import Options.Applicative
main :: IO ()
main = print =<< execParser options
where
opts = sample `withInfo` "Print a greeting for TARGET"
data Sample = Sample { hello :: String, verbose :: Bool }
sample :: Parser Sample
sample = Sample
<$> strOption ( long "hello" <> help ".." )
<*> switch ( long "verbose" <> short 'v' <> help ".." )
withInfo :: Parser a -> String -> ParserInfo a
withInfo opts = info (helper <*> opts) . progDesc
optparse-applicative  でサブコマンド
(おまけ話?本題?)
なんか ToDo タスクを処理できそうなサブコマンドの
型
data SubCmd
= NewCmd
| AddCmd Int Text
| DoneCmd Int
| ListCmd
deriving (Show, Eq)
optparse-applicative でサブコマンド
サブコマンドのパーサー
subcmdParser :: Parser SubCmd
subcmdParser = subparser
$ command "new" (pure NewCmd `withInfo` "...")
<> command "add" (AddCmd <$> ... `withInfo` "...")
<> command "done" (DoneCmd <$> ... `withInfo` "...")
<> command "list" (pure ListCmd `withInfo` "...")
hoge new  とか  hoge add  ってサブコマンドになる
Semigroup  の結合( <> )しかしてないんで網羅性チェッ
クは無理
拡張可能バリアントの導入
extensible というパッケージを使います
type SubCmd = Variant
'[ "new" >: ()
, "add" >: (Int, Text)
, "done" >: Int
, "list" >: ()
]
(extensible については wiki を参照してください)
拡張可能バリアントの導入
これで網羅性のチェックをしてくれるし、
ついでにサブコマンド文字列も自動で導出
subcmdParser :: Parser SubCmd
subcmdParser = variantFrom -- `variantFrom` 関数は自作
$ #new @= (pure () `withInfo` "...")
<: #add @= (... `withInfo` "...")
<: #done @= (... `withInfo` "...")
<: #list @= (pure () `withInfo` "...")
<: nil
詳しくは: オレ的 Haskell で CLI を作る方法 2018 ­
ひげメモ の extensible で optparse­applicative
拡張可能バリアントの導入
variantFrom ::
Forall (KeyIs KnownSymbol) xs =>
RecordOf ParserInfo xs -> Parser (Variant xs)
variantFrom = subparser . subcmdVariant
where
subcmdVariant =
hfoldMapWithIndexFor (Proxy @ (KeyIs KnownSymbol))
$ m x ->
let k = symbolVal (proxyAssocKey m)
in command k
((EmbedAt m . Field . pure) <$> getField x)
instance Wrapper ParserInfo where
type Repr ParserInfo a = ParserInfo a
_Wrapper = id
Alt. Prelude
Haskell の標準ライブラリ
(Haskell というか GHC というか)
base  という名前
Prelude というモジュールが標準インポート
NoImplicitPrelude  プラグマでオフにできる
標準ライブラリの代替
昔,Haskell­jp Slack で話題に上がった
slack­link (いずれなくなると思う)
classy­prelude
universum
rio
protolude
などなど
RIO ライブラリ
stack を開発しているチームが開発している
彼らのベストプラクティスをを詰め込んである
大域環境・ログ・エラーハンドリング
よく使うライブラリのラッパー
text ,  bytestring ,  directory ,  filepath
containers ,  lens ,  time ,  vector
などなど
RIO ライブラリの使用例
run :: RIO Env () -> Options -> IO ()
run cmd opts = do
token <- liftIO $ getEnv "MEDIUM_TOKEN"
logOpts <- logOptionsHandle stdout (opts ^. #verbose)
withLogFunc logOpts $ logger -> do
let env = #logger @= logger
<: #token @= fromString token
<: nil
runRIO env cmd
callMeAPI :: RIO Env ()
callMeAPI = do
logDebug "Run cmd: call me api"
token <- asks (view #token)
user <- API.getMe token
logDebug $ display ("get: " <> tshow user)
logInfo $ display ("Hi " <> user ^. #name <> "!!")
実行してみる
$ mdium --version
Version 0.2.0.0, Git revision
efcf1856b6b065141a6d366663b97b0301053ffd (23 commits)
$ mdium --verbose --me
2018-11-10 10:28:53.049919: [debug] Run cmd: call me api
@(src/Mdium/Cmd/Run.hs:57:3)
2018-11-10 10:28:54.721968: [debug] get: id @= "..." <:
username @= "nobutada" <: name @= "matsubara" <: url @=
"https://medium.com/@nobutada" <: imageUrl @= ".." <: nil
@(src/Mdium/Cmd/Run.hs:60:3)
2018-11-10 10:28:54.722133: [info] Hi matsubara!!
@(src/Mdium/Cmd/Run.hs:61:3)
Stack Template
Haskell Stack
Haskell のビルドツール
処理系自体は GHC
プロジェクト内の各パッケージのバージョン管理
などなど
$ stack new sample hoge-template
$ cd sample-project
$ stack build
$ stack exec -- application
stack new  の後がパターン化
stack new  した後に各基本的なコードが同じ
よく使うパッケージを  package.yaml  に追加
コマンドライン引数の処理する部分を追加
などなど
これを「オレオレテンプレート化」できる
自作テンプレートの例 (hsfiles)
{-# START_FILE package.yaml #-}
name: {{name}}
version: 0.1.0.0
homepage: https://github.com/{{github-username}}/{{name}}
...
dependencies:
- base >= 4.7 && < 5
- rio >= 0.1.1.0
- extensible >= 0.4.9
- yaml
...
{-# START_FILE app/Main.hs #-}
module Main where
import RIO
import Data.Extensible
...
公開できる!
今まではテンプレートファイルを特定のローカルパス
に置く必要があった.
stack­1.9 から GitHub, GitLab, BitBucket のリポジト
リから取得できる.
$ stack new sample github:matsubara0507/hoge.hsfiles
詳しくは: namespaced templates ­ BIG MOON
こんな感じ
おまけ: stack­tpls
matsubara0507/stack­tpls ­ GitHub
公開されているテンプレートを取得するコマンド
(まだ GitHub にしか対応していない...)
$ stack-tpls -l
github:commercialhaskell/chrisdone.hsfiles
github:commercialhaskell/foundation.hsfiles
github:commercialhaskell/franklinchen.hsfiles
github:commercialhaskell/ghcjs-old-base.hsfiles
github:commercialhaskell/ghcjs.hsfiles
github:commercialhaskell/hakyll-template.hsfiles
...
まとめ
コマンドライン引数の取得方法はいろいろ
単純なものからリッチなものまで
標準ライブラリや Prelude が微妙と思い始めたら
Alt. Prelude を探そう
オレオレプラクティスやパターンが出てきたらテ
ンプレート化しよう
(stack­tpls 使ってみて)
おしまい

More Related Content

PPTX
ActiveResourceが面白すぎる件
PDF
awk v.s. bashどっちが強い?@OSC2011Tokyo
PDF
What is Metasepi?
PPTX
前期講座09
PDF
サーバーサイドでの非同期処理で色々やったよ
PDF
PythonでLispを実装した (evalつき)
PDF
Functional Way
PDF
おいしいLisp
ActiveResourceが面白すぎる件
awk v.s. bashどっちが強い?@OSC2011Tokyo
What is Metasepi?
前期講座09
サーバーサイドでの非同期処理で色々やったよ
PythonでLispを実装した (evalつき)
Functional Way
おいしいLisp

What's hot (20)

PDF
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
PPTX
php7's ast
PDF
HashTable と HashDos
PDF
Everyday Life with clojure.spec
PDF
Array twitter2
PDF
200319 eash python_shareslide_functions
KEY
Applicative functor
PPT
CPANの依存モジュールをもう少し正しく検出したい
PPTX
XMonad-oid on Emacs & More functional Emacs Lisp | 関数型LT大会
PDF
PHP5.5新機能「ジェネレータ」初心者入門
KEY
Stroustrup11章雑感
PDF
Java SE 8 lambdaで変わる プログラミングスタイル
PDF
(Ruby使いのための)Scalaで学ぶ関数型プログラミング
PDF
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
PDF
「Grails-1.1を斬る!〜Grails-1.1からのチーム開発〜」
PDF
Composable Callbacks & Listeners
PDF
Local php-100828 2
PDF
Data processing at spotify using scio
PDF
データサイエンスワールドからC++を眺めてみる
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
php7's ast
HashTable と HashDos
Everyday Life with clojure.spec
Array twitter2
200319 eash python_shareslide_functions
Applicative functor
CPANの依存モジュールをもう少し正しく検出したい
XMonad-oid on Emacs & More functional Emacs Lisp | 関数型LT大会
PHP5.5新機能「ジェネレータ」初心者入門
Stroustrup11章雑感
Java SE 8 lambdaで変わる プログラミングスタイル
(Ruby使いのための)Scalaで学ぶ関数型プログラミング
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
「Grails-1.1を斬る!〜Grails-1.1からのチーム開発〜」
Composable Callbacks & Listeners
Local php-100828 2
Data processing at spotify using scio
データサイエンスワールドからC++を眺めてみる
Ad

Similar to Haskell で CLI (20)

PPTX
やや関数型を意識した風Elixir/Phoenixご紹介
PPTX
PHP AST 徹底解説
PDF
Start printf 6_takarakasai
PPT
Scala on Hadoop
PDF
from old Java to modern Java
PDF
ScalaプログラマのためのHaskell入門
PDF
BOF1-Scala02.pdf
PDF
BOF1-Scala02.pdf
PDF
BOF1-Scala02.pdf
PDF
イマドキの現場で使えるJavaライブラリ事情
PDF
asm.js x emscripten: The foundation of the next level Web games
PPTX
ゼロから始めるScala文法 (再)
PDF
GNU awk (gawk) を用いた Apache ログ解析方法
PDF
MapReduce入門
PDF
関数型言語テイスティング: Haskell, Scala, Clojure, Elixirを比べて味わう関数型プログラミングの旨さ
PDF
Pfi Seminar 2010 1 7
PPTX
PPTX
Java8から始める関数型プログラミング
PDF
第三回ありえる社内勉強会 「いわががのLombok」
PDF
純LISPから考える関数型言語のプリミティブ: Clojure, Elixir, Haskell, Scala
やや関数型を意識した風Elixir/Phoenixご紹介
PHP AST 徹底解説
Start printf 6_takarakasai
Scala on Hadoop
from old Java to modern Java
ScalaプログラマのためのHaskell入門
BOF1-Scala02.pdf
BOF1-Scala02.pdf
BOF1-Scala02.pdf
イマドキの現場で使えるJavaライブラリ事情
asm.js x emscripten: The foundation of the next level Web games
ゼロから始めるScala文法 (再)
GNU awk (gawk) を用いた Apache ログ解析方法
MapReduce入門
関数型言語テイスティング: Haskell, Scala, Clojure, Elixirを比べて味わう関数型プログラミングの旨さ
Pfi Seminar 2010 1 7
Java8から始める関数型プログラミング
第三回ありえる社内勉強会 「いわががのLombok」
純LISPから考える関数型言語のプリミティブ: Clojure, Elixir, Haskell, Scala
Ad

More from Nobutada Matsubara (20)

PDF
Haskell で作る競技型イベントの裏側
PDF
Marp Next Theme: Colors
PDF
Marp Next Tips !
PDF
貧者のための「cron」
PDF
Build Dockferile with Haskell
PDF
Elixir Programming with Type checking
PDF
MixML 作ってみる
PDF
Elm でなんかつくる
PDF
Haskell と Elm と JSON の話
PDF
ADVENTAR の Bot を作る with Haskell
PDF
Haskell Backpack 事始め
PDF
GitHub での Haskell の色が変わったんで
PDF
日記って続かないよね...
PDF
「7つの言語、7つの世界」を読む
PDF
Lisper はじめました (再)
PDF
Haskell で LINE Bot を作ってみた
PDF
Marp colors
PDF
PDF
Whitespcae 入門
PDF
入門 超絶技巧プログラミング !
Haskell で作る競技型イベントの裏側
Marp Next Theme: Colors
Marp Next Tips !
貧者のための「cron」
Build Dockferile with Haskell
Elixir Programming with Type checking
MixML 作ってみる
Elm でなんかつくる
Haskell と Elm と JSON の話
ADVENTAR の Bot を作る with Haskell
Haskell Backpack 事始め
GitHub での Haskell の色が変わったんで
日記って続かないよね...
「7つの言語、7つの世界」を読む
Lisper はじめました (再)
Haskell で LINE Bot を作ってみた
Marp colors
Whitespcae 入門
入門 超絶技巧プログラミング !

Haskell で CLI