HaskellでStateモナドを自作する

Stateモナドがわからない状態から、ギリギリ分かる状態になった。 Stateモナドを学習した流れ 結局、具体例を通して学習した。個人的には、いきなりモナドの定義から学習するよりも、たくさんの例を見たり、実際に例を作ってみたりした方が覚えられた。抽象的な概念を理解するためには具体的な概念に触れるべきだ、ということを改めて認識した。 以下は、自分が行った学習の流れ。Haskell IOモナド 超入門は学習のうえで参考になった。とくに、>>=を漏斗の形に見立てる比喩のおかげで、モナドと関数の組み合わせのイメージがクリアになった。 Maybeモナド、Listモナドの使い方を理解する。 IOモナドの使い方を理解する。 いくつかのモナドについて、do構文を>>=に書き換えてみる。 Stateモナドの使い方を理解する。 Stateモナドを自作する。 この記事ではStateモナドを自作することをテーマとしているため、ある程度Stateモナドに慣れた人でないとわかりづらいかもしれない。 Stateの定義 まずはStateを自作する。Stateは、状態 -> (計算結果,次の状態)という関数を内部に持っている。この関数のことを、この記事では「内部関数」「状態付き計算」などと表現する。 1 newtype State s a = State (s -> (a, s)) これは本来のStateの定義とは異なることに注意。本来は、StateはStateTを使って実装されている。上のように定義してしまうと、モナド変換子としての機能が利用できない。ただ、そこまで考えると面倒なので、今回はStateを単なる関数のラッパーとして定義した。 型引数の順番と内部関数が返すタプルの順番が逆なのが微妙に気持ち悪い。これはあくまで推測でしかないが、 あくまで状態付きの計算なので、重要なのは計算の結果。なので返り値は(a, s)と計算結果を先に書いている。 型引数の順番がs aなのは、Monadにするときに不都合を生じないため。 なのだと思う。 余談 Stateモナドがよくわかっていない時は、Stateのことを「状態を持つ型」と勘違いしていた。正しくは、「状態付き計算を持つ型」。Stateは状態を持っているわけでなく、あくまで、「状態を引数にとり、計算結果と次の状態を返す関数」を持っている。なので、初期状態は内部関数の引数として、自分で投入する。 runStateの定義 レコード構文を使って、runStateを定義する。runStateは、Stateから中身の関数を取り出す関数。 1 newtype State s a = State { runState :: s -> (a, s) } 試す 上の定義を踏まえて、次のようにプログラムを書いてみる。以下は、状態を[Int]とする状態付き計算。 addX doubleAll sumUpはそれぞれ、単純な内部関数を持つStateである。一方で、calc0はこれらの関数を組み合わせた、新たなStateであることに注目。一連の状態付き計算を一つにまとめて、新たな状態付き計算を作っている。 calc0において、初期状態をs、次の状態をs0、その次の状態をs1、…と置いている。計算結果を返すのはsumUpだけで、他の関数は単に状態を変更するだけ。なので計算結果は()となっている。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 addX :: Int -> State [Int] () addX x = State $ \s -> ((), x:s) doubleAll :: State [Int] () doubleAll = State $ \s -> ((), map (* 2) s) sumUp :: State [Int] Int sumUp = State $ \s -> (sum s, s) calc0 :: State [Int] Int calc0 = State $ \s -> let (_, s0) = runState (addX 1) s (_, s1) = runState (addX 2) s0 (a2, s2) = runState sumUp s1 (_, s3) = runState (addX a2) s2 (_, s4) = runState doubleAll s3 in runState sumUp s4 main = do print $ runState calc0 [] 実行結果は以下のようになる。 ...

2020-03-28 · (updated 2020-03-29) · 8 min · 1531 words

webpackに入門する - p5.jsの開発環境作り

webpackを利用してp5.jsの開発環境を作り、ボールが弾むプログラムを作成する。 使用するパッケージのバージョン 1 2 3 4 webpack@5.15.0 webpack-cli@4.3.1 webpack-dev-server@3.11.2 p5@1.2.0 動機 ふとしたきっかけで久々にp5.jsを触りたくなった。 昔使っていたときは、p5.jsのファイルをダウンロードしてscriptタグに直接指定することで書いていた。しかし最近、Vue.jsのガイドを読んでいてwebpackの存在を知った。名前は知っていたのだが、具体的に何をするためのものなのかはよく分かっていなかったので調べた。 webpackとは 以下、個人的に調べた限りの理解を書く。 Conceptによれば、webpackとは"module bundler"の一種。bundleという意味から、「複数のモジュールを一つに束ねるツール」だと予想できる。JSのプログラムを、モジュールとして複数の単位に分割して開発する。それを一つのファイルにまとめ上げてくれるのがwebpack。 例えばp5.jsで、ボールが弾むだけのプログラムを書こう、と思った場合、 ボールを管理するモジュールをBall.jsに書く スケッチを管理するモジュールをsketch.jsに書く メインの処理をindex.jsに書く みたいにモジュールを分けられる。 ただし、モジュールを扱うための機能であるimport/export文はES2015の仕様で標準採用され、多くのブラウザで実装されている。じゃあwebpackの他の強みは何かというと、おそらく「JS以外のファイルもまとめてくれる点」だと思う。例えばcssやsassのファイルもJSに埋め込むことができる。TypeScriptやJSXのファイルもwebpackでまとめられる。ただしwebpackの核の機能はあくまでJSのモジュールをまとめることなので、JS以外のファイルはloaderと呼ばれる変換器を通しておく必要がある。とはいえ、「このファイルはこのloaderに通してね」というのをあらかじめ設定ファイルに書いておけば、少ないコマンドで変換からbundleまでやってくれるので、便利である。 今回はp5.jsの開発環境づくりのためにwebpackを用意するのだが、JSのモジュールしか扱うつもりはない。なのでwebpackの恩恵は少ないかもしれない。しかし練習として使ってみる。 webpackの導入と動作確認 まず適当にプロジェクト用のディレクトリを作る。npmでプロジェクトを初期化する。 $ mkdir p5-sandbox $ cd p5-sandbox $ npm init -y 以下、このプロジェクトのルートディレクトリを/で表す。 webpack本体を入れる。webpackをコマンドラインから実行するためにはwebpack-cliが必要なので、それも入れる。個人で使う分にはどうでもよいと思うが、これらは開発のみに利用されるパッケージなので、--save-devをつけておく。 $ npm install webpack webpack-cli --save-dev ディレクトリの作成 今回は次のようにする。 ソースコードは/src/index.jsに書く。 bundle後のファイルは/public/js/bundle.jsとして出力されるようにする。 あらかじめディレクトリを作成しておく。 $ mkdir src $ mkdir -p public/js index.jsの作成 /src/index.jsを作成。動作確認のため適当に書く。 1 console.log("Hello, World"); webpackの設定 /webpack.config.jsを作成する。 1 2 3 4 5 6 7 8 9 10 const path = require('path'); module.exports = { mode: 'development', entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'public/js') } } 説明 module.exportsの中に色々設定項目を書いていく。基本的なことはConfigurationに載っている。 ...

2020-03-19 · (updated 2021-01-17) · 3 min · 629 words

zipファイルの構造を少しだけ理解する

Unix系のコマンド(od、grep)だけを使って、zipファイルの中身をのぞく。 zip形式の参考サイト zipの仕様書はZIP File Format Specificationで確認できる。ページ内検索をかけながら必要なところをつまんでいく、という読み方が良さそう。 日本語ならWikipediaがある。こちらは図が書かれているし日本語なので分かりやすい。 zipファイルの用意 まずはzipファイルを用意する。 foo.txtとbar.txtを用意する。 $ echo "Hello, World." > foo.txt $ echo "Good Bye." > bar.txt これらをzipコマンドでまとめる。 $ zip tmp.zip foo.txt bar.txt バイナリ形式で出力 zipファイルはテキストとして表示できるものではなく、バイナリとして表示しないとあまり意味を掴めない。バイナリ表示ができるテキストエディタを使ってもよいが、ここではodコマンドを用いる。 $ od -Ax -tx1z tmp.zip 引数の意味は以下の通り。man odでも確認できる。 -A: アドレスの基数(Address-radix)。出力時、最も左の値がファイル先頭から何バイト目なのかを表示する。続けてxと書くと、16進数(hex)で出力する。 -t: データの出力形式(おそらくtypeの略)。 続けてx1と書くと、1バイト区切りの16進数で出力する。 続けてzと書くと、右側にテキストでの表示を添える。ただし表示されるのはASCIIコードで認識される文字のみ。 結果は以下のようになる。 000000 50 4b 03 04 0a 00 00 00 00 00 28 70 64 50 4b 82 >PK........(pdPK.< 000010 70 33 0e 00 00 00 0e 00 00 00 07 00 1c 00 66 6f >p3............fo< 000020 6f 2e 74 78 74 55 54 09 00 03 1b 36 5f 5e 1b 36 >o.txtUT....6_^.6< 000030 5f 5e 75 78 0b 00 01 04 e8 03 00 00 04 e8 03 00 >_^ux............< 000040 00 48 65 6c 6c 6f 2c 20 57 6f 72 6c 64 2e 0a 50 >.Hello, World..P< 000050 4b 03 04 0a 00 00 00 00 00 2b 70 64 50 cb e8 62 >K........+pdP..b< 000060 fc 0a 00 00 00 0a 00 00 00 07 00 1c 00 62 61 72 >.............bar< 000070 2e 74 78 74 55 54 09 00 03 21 36 5f 5e 21 36 5f >.txtUT...!6_^!6_< 000080 5e 75 78 0b 00 01 04 e8 03 00 00 04 e8 03 00 00 >^ux.............< 000090 47 6f 6f 64 20 42 79 65 2e 0a 50 4b 01 02 1e 03 >Good Bye..PK....< 0000a0 0a 00 00 00 00 00 28 70 64 50 4b 82 70 33 0e 00 >......(pdPK.p3..< 0000b0 00 00 0e 00 00 00 07 00 18 00 00 00 00 00 01 00 >................< 0000c0 00 00 a4 81 00 00 00 00 66 6f 6f 2e 74 78 74 55 >........foo.txtU< 0000d0 54 05 00 03 1b 36 5f 5e 75 78 0b 00 01 04 e8 03 >T....6_^ux......< 0000e0 00 00 04 e8 03 00 00 50 4b 01 02 1e 03 0a 00 00 >.......PK.......< 0000f0 00 00 00 2b 70 64 50 cb e8 62 fc 0a 00 00 00 0a >...+pdP..b......< 000100 00 00 00 07 00 18 00 00 00 00 00 01 00 00 00 a4 >................< 000110 81 4f 00 00 00 62 61 72 2e 74 78 74 55 54 05 00 >.O...bar.txtUT..< 000120 03 21 36 5f 5e 75 78 0b 00 01 04 e8 03 00 00 04 >.!6_^ux.........< 000130 e8 03 00 00 50 4b 05 06 00 00 00 00 02 00 02 00 >....PK..........< 000140 9a 00 00 00 9a 00 00 00 00 00 >..........< 00014a シグネチャ zipファイルは以下のような要素を持つ。 ...

2020-03-04 · (updated 2020-03-06) · 14 min · 2935 words

Elmメモ ドラッグ移動の実現(2) - elm-draggableの利用

前回はBrowsertやSvgなどの標準的なパッケージを利用してドラッグ機能を実現した。今回はelm-draggableというパッケージを使ってドラッグ機能を実現してみる。 準備 Elmのプロジェクトを作成して、src/Main.elmとsrc/Circle.elmを作成。 Circle.elm 前回と同じなのでコードだけ載せる。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 module Circle exposing (..) type alias Id = Int type alias Circle = { id : Id , x : Float , y : Float , r : Float } type alias Circles = { all : List Circle , nextId : Id } empty : Circles empty = { all = [] , nextId = 0 } type alias CircleNoId = { x : Float , y : Float , r : Float } add : CircleNoId -> Circles -> Circles add c circles = let circle = { id = circles.nextId , x = c.x , y = c.y , r = c.r } in { circles | all = circle :: circles.all , nextId = circles.nextId + 1 } fromList : List CircleNoId -> Circles fromList list = { all = List.indexedMap (\i c -> { id = i, x = c.x, y = c.y, r = c.r }) list , nextId = List.length list } toList : Circles -> List Circle toList circles = circles.all update : Id -> (Circle -> Circle) -> Circles -> Circles update id f circles = let new = List.foldr (\c acc -> if c.id == id then f c :: acc else c :: acc ) [] circles.all in { circles | all = new } Main.elm Circlesを描画するところまで書く。 ...

2020-02-27 · (updated 2020-02-27) · 6 min · 1148 words

Elmメモ ドラッグ移動の実現(1)

ElmでSVGの要素をドラッグ移動したいと思った。ドラッグ操作を実現するパッケージにelm-draggableがある。今回は勉強として、それに頼らず実装することを試みる。elm-draggableを用いた方法については次回やる。 初期状態 詳細は省略するが、Elmプロジェクトを作成してelm/svgとelm/jsonをインストールしておく。 src/Main.elmは以下のようにしておく。elm reactorで動くことを確認する。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 module Main exposing (..) import Browser import Browser.Events as BE import Html exposing (..) import Html.Attributes exposing (..) import Json.Decode as JD import Svg as S exposing (Svg) import Svg.Attributes as SA import Svg.Events as SE main = Browser.element { init = init , update = update , view = view , subscriptions = subscriptions } type alias Model = {} type Msg = Dummy init : () -> ( Model, Cmd Msg ) init _ = ( {}, Cmd.none ) update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = ( model, Cmd.none ) view : Model -> Html Msg view model = div [] [] subscriptions : Model -> Sub Msg subscriptions model = Sub.none 目標 SVGの領域に円が複数存在する 円をドラッグ移動できるようにしたい。 円のドラッグ中はその色を橙色にし、それ以外のときは白にする 方針 ドラッグ処理については次の処理で実現することになる。 ...

2020-02-25 · (updated 2020-03-04) · 8 min · 1588 words

Vue.js勉強メモ(1) - 簡易Todoリストの作成

公式ガイドの、コンポーネントの詳細の手前まで読み終えたので、この時点でTodoリストっぽいものを作ってみる。データベースを用意しないため、厳密にはTodoリストではない。 コンポーネントについてはまだ学んでいないため、これから書くコードにはまだ改善の余地があるだろう。 準備 index.htmlを用意する。 1 2 3 4 5 6 7 8 9 10 11 <!DOCTYPE html> <html lang="ja"> <head> <meta charet="utf-8"> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <h1>Todo List</h1> <script src="script.js"></script> </body> </html> 以下の部分でVue.jsを読み込んでいる。 1 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> script.jsを作成しておく。中身はまだ空。 実装する機能 初めにも述べたが、データベースは用意しない。以下の簡単な機能だけ実装する。 入力エリア Todoリスト表示エリア 各要素に削除ボタンをつける。 勉強を兼ねて、いくらか遠回りしながら作っていく。 配列の要素をli要素として表示 index.htmlに追記する。 1 2 3 4 5 <div id="app"> <ul> <li v-for="todo in todos">{{ todo }}</li> </ul> </div> Vue.jsが用意したテンプレート構文をHTMLに埋め込むことによって、データとDOMを結びつけることができる。v-という接頭辞がついた属性はディレクティブと呼ばれる。今回のv-forディレクティブは、その名の通りfor文を実現する。構文から分かると思うが、JSとかPythonで使われているfor-in文と同じ文法。 式の埋め込みは{{ 式 }}で行う。ガイドではMustache(口髭)構文と呼んでいる。良いネーミングだなと思ったけど、{{ }}の書式をそう呼ぶのはわりと一般的みたい? ...

2020-02-16 · (updated 2020-02-16) · 2 min · 306 words

GraphvizでTeXの数式を表示する(2) - PDFにしたい場合

TeXのレポートに貼り付けたいが、TeXではSVG形式は扱えないのでPDFにしたくなった。やってみたら思ったより面倒だったので備忘録として残す。 dotファイルの用意 前回と同じにする。ファイル名はgraph.dotとする。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 digraph { graph [ rankdir="LR" ]; node [ shape="circle", fixedsize=true, height=0.6 ]; Q0 [texlbl="$q_0$"]; Q1 [texlbl="$q_1$"]; Q2 [texlbl="$q_2$"]; Q3 [texlbl="$q_3$"]; Q4 [texlbl="$q_4$"]; Q5 [texlbl="$q_5$"]; Q6 [texlbl="$q_6$"]; Q7 [texlbl="$q_7$"]; Q8 [texlbl="$q_8$"]; Q9 [texlbl="$q_9$"]; Q10 [texlbl="$q_{10}$"]; Q11 [texlbl="$q_{11}$"]; Q12 [texlbl="$q_{12}$"]; Q13 [texlbl="$q_{13}$"]; Q0 -> Q1 [label=" ", texlbl="$\varepsilon$"]; Q0 -> Q4 [label=" ", texlbl="$\varepsilon$"]; Q0 -> Q7 [label=" ", texlbl="$\varepsilon$"]; Q1 -> Q2 [label=" ", texlbl="$a$"]; Q2 -> Q3 [label=" ", texlbl="$b$"]; Q3 -> Q7 [label=" ", texlbl="$\varepsilon$"]; Q4 -> Q5 [label=" ", texlbl="$b$"]; Q5 -> Q6 [label=" ", texlbl="$b$"]; Q6 -> Q7 [label=" ", texlbl="$\varepsilon$"]; Q7 -> Q8 [label=" ", texlbl="$a$"]; Q7 -> Q0 [label=" ", texlbl="$\varepsilon$"]; Q8 -> Q9 [label=" ", texlbl="$\varepsilon$"]; Q8 -> Q11 [label=" ", texlbl="$\varepsilon$"]; Q9 -> Q10 [label=" ", texlbl="$b$"]; Q10 -> Q13 [label=" ", texlbl="$\varepsilon$"]; Q11 -> Q12 [label=" ", texlbl="$c$"]; Q12 -> Q13 [label=" ", texlbl="$\varepsilon$"]; } dot → tex $ dot2tex graph.dot > graph.tex tex → pdf 駄目なパターン $ platex graph.tex $ dvipdf graph.dvi これをやると、一部が画面からはみ出したグラフが作成されてしまう。 ...

2020-02-11 · (updated 2020-02-11) · 2 min · 290 words

GraphvizでTeXの数式を表示する(1)

Graphvizはグラフを描画してくれる素晴らしいソフトなのだが、単体では数式を表示することができない。 dot2tex dot2texを利用すると、グラフのラベルに数式が使えるようになる。 次の手順でグラフを作る。 dot言語でグラフを書く dot2texでdotファイルをtexファイルに変換 texを使ってpdfなりsvgなりを作る。 pdfならplatex + dvipdfを使う(詳細は別記事にて) svgならplatex + dvisvgmを使う。 いやGraphviz使ってないじゃないか、と思うかもしれない。しかしDependensiesにGraphvizが含まれているから、おそらくGraphvizの描画エンジンを利用してノードの位置を決定しているのだと思う。 インストール Python製のソフトウェアみたいで、pip経由でインストールする。 $ pip3 install dot2tex 利用の手順 dot言語でグラフを書く 今回は次のようにする。ファイル名は適当にgraph.dotとする。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 digraph { graph [ rankdir="LR" ] node [ shape="circle", fixedsize=true, height=0.6 ] Q0 [texlbl="$q_0$"]; Q1 [texlbl="$q_1$"]; Q2 [texlbl="$q_2$"]; Q3 [texlbl="$q_3$"]; Q4 [texlbl="$q_4$"]; Q5 [texlbl="$q_5$"]; Q6 [texlbl="$q_6$"]; Q7 [texlbl="$q_7$"]; Q8 [texlbl="$q_8$"]; Q9 [texlbl="$q_9$"]; Q10 [texlbl="$q_{10}$"]; Q11 [texlbl="$q_{11}$"]; Q12 [texlbl="$q_{12}$"]; Q13 [texlbl="$q_{13}$"]; Q0 -> Q1 [label=" ", texlbl="$\varepsilon$"]; Q0 -> Q4 [label=" ", texlbl="$\varepsilon$"]; Q0 -> Q7 [label=" ", texlbl="$\varepsilon$"]; Q1 -> Q2 [label=" ", texlbl="$a$"]; Q2 -> Q3 [label=" ", texlbl="$b$"]; Q3 -> Q7 [label=" ", texlbl="$\varepsilon$"]; Q4 -> Q5 [label=" ", texlbl="$b$"]; Q5 -> Q6 [label=" ", texlbl="$b$"]; Q6 -> Q7 [label=" ", texlbl="$\varepsilon$"]; Q7 -> Q8 [label=" ", texlbl="$a$"]; Q7 -> Q0 [label=" ", texlbl="$\varepsilon$"]; Q8 -> Q9 [label=" ", texlbl="$\varepsilon$"]; Q8 -> Q11 [label=" ", texlbl="$\varepsilon$"]; Q9 -> Q10 [label=" ", texlbl="$b$"]; Q10 -> Q13 [label=" ", texlbl="$\varepsilon$"]; Q11 -> Q12 [label=" ", texlbl="$c$"]; Q12 -> Q13 [label=" ", texlbl="$\varepsilon$"]; } texlblとはdot2texが読むための属性。おそらくtex labelの略で、これがnodeまたはedgeのラベルとして、texファイルに直接展開される。そのため、数式を描きたいなら$で囲む。もしdotファイル上にlabel属性が定義されていたら、texlblの内容に上書きされる。 ...

2020-01-26 · (updated 2020-02-11) · 2 min · 224 words

Elmメモ - 画像のプレビュー機能を作る

Elmを利用して、画像を選択してそれを表示するアプリを作る。 ファイル読み込みの方法 Select.file関数を利用する。これはファイル選択用のエクスプローラを開くためのCmd Msgを作成してくれる。選択したファイルはMsgに載せられる。 適切なMIMEタイプを指定すると、エクスプローラ上にてそのタイプのファイルしか選択できなくなる。例えば、text/plainを選択しておけば、拡張子.txtのファイルしか選択できなくなる。 1 Select.file "MIMEタイプのリスト" "Msg" 画像ファイルへの変換 こうして得られたファイルはFileと呼ばれる型で保持される。 もしファイルを文字列として扱いたいなら、File.toStringを利用する。 もし画像として扱いたいなら、File.toUrlを利用する。これは画像をBase64符号化した文字列を作る。これをimgタグのsrc属性に指定すれば、画像が表示される。 画像を選択し、それを表示するアプリの作成 準備 プロジェクトを作成して、elm/fileをインストール。 $ elm init $ elm install elm/file src/Main.elmの雛形を作る。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 module Main exposing (..) import Browser import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (..) import File exposing (File) import File.Select as Select import Task main = Browser.element { init = init , update = update , view = view , subscriptions = subscriptions } type alias Model = { } init : () -> (Model, Cmd Msg) init _ = ( { } , Cmd.none ) type Msg = Msg update : Msg -> Model -> (Model, Cmd Msg) update msg model = ( model , Cmd.none ) view : Model -> Html Msg view model = div [] [ ] subscriptions : Model -> Sub Msg subscriptions model = Sub.none htmlファイルを自分で作りたいので、makeのときはjsファイルを単独で生成させる。 ...

2020-01-13 · (updated 2020-01-13) · 4 min · 699 words

Elmメモ - 文字列をIPアドレスに変換(2) Parserを用いる方法

準備 前回のsrc/IPAddr.elmを全て消し、内容を以下の通りにする。 1 2 3 4 5 module IPAddr exposing (..) import Parser type IPAddr = IPAddr Int Int Int Int $ elm repl > import Parser exposing (..) > import IPAddr exposing (..) Parserの基本 以下の2つのステップに分かれる。 Parserを作る Parserを実行する - Parser.runを用いる ライブラリでは、標準で用意されているParserと、それらを組み合わせて新たなParserを作るための関数が用意されている。 > run int "123" Ok 123 : Result (List Parser.DeadEnd) Int > run int "123abc" Ok 123 : Result (List Parser.DeadEnd) Int > run int "abc123abc" Err [{ col = 1, problem = ExpectingInt, row = 1 }] : Result (List Parser.DeadEnd) Int succeed 何もパースせず、決まった結果だけを返すパーサー。 > run (succeed "Hello") "123abcde" Ok "Hello" : Result (List Parser.DeadEnd) String パーサーを組み合わせるときの基本になる。 ...

2020-01-05 · (updated 2020-01-05) · 3 min · 549 words