├── .circleci
└── config.yml
├── .github
├── ISSUE_TEMPLATE
│ └── topic-request.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── Setup.hs
├── examples
├── 2019
│ └── hiw-copilot
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── heater.hs
│ │ ├── stack.yaml
│ │ └── stack.yaml.lock
└── 2020
│ └── strict-gotchas
│ ├── README.md
│ ├── const.hs
│ ├── stack.yaml
│ ├── stack.yaml.lock
│ ├── stackoverflow-foldr.hs
│ ├── storable.hs
│ └── where.hs
├── haskell-jp-blog.cabal
├── preprocessed-site
├── .circleci
│ └── config.yml
├── LICENSE
├── README.md
├── css
│ ├── bootstrap.css
│ ├── clean-blog.css
│ └── style.css
├── feed.md
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ └── glyphicons-halflings-regular.woff2
├── img
│ ├── 2017
│ │ ├── 12-rts-coverage1.png
│ │ ├── 12-rts-coverage2.png
│ │ ├── 12-rts-space-profile.png
│ │ ├── 12-rts-threadscope.png
│ │ └── 13-01-kind-graph.png
│ ├── 2018
│ │ ├── haskell-day-2018
│ │ │ ├── _DSC1173.jpg
│ │ │ ├── _DSC1176.jpg
│ │ │ ├── _DSC1177.jpg
│ │ │ ├── _DSC1178.jpg
│ │ │ ├── _DSC1179.jpg
│ │ │ ├── _DSC1183.jpg
│ │ │ ├── _DSC1186.jpg
│ │ │ ├── _DSC1191.jpg
│ │ │ ├── _DSC1193.jpg
│ │ │ ├── _DSC1194.jpg
│ │ │ ├── aiya000.png
│ │ │ ├── connpass.png
│ │ │ ├── fumieval.png
│ │ │ ├── khibino.png
│ │ │ ├── lotz.png
│ │ │ ├── questionnaire1.png
│ │ │ └── questionnaire2.png
│ │ └── tech-book-fest-5-banner.png
│ ├── 2019
│ │ ├── fallible
│ │ │ └── slack.jpg
│ │ ├── haskell-day-2019
│ │ │ ├── after-party.jpg
│ │ │ ├── aiya000.jpg
│ │ │ ├── egison.jpg
│ │ │ ├── ekmett.jpg
│ │ │ ├── fumieval.jpg
│ │ │ ├── lotz.jpg
│ │ │ ├── matsubara0507.jpg
│ │ │ ├── mr_konn.jpg
│ │ │ ├── nobsun.jpg
│ │ │ ├── question1.jpg
│ │ │ ├── question2.jpg
│ │ │ ├── question3.jpg
│ │ │ ├── question4.jpg
│ │ │ ├── question5.jpg
│ │ │ ├── question6.jpg
│ │ │ └── y_taka_23.jpg
│ │ ├── haskell-in-vrchat
│ │ │ ├── vrc-lt-control-panel.png
│ │ │ ├── vrc-lt-image.png
│ │ │ ├── vrc-lt-room.png
│ │ │ └── vrc-lt.png
│ │ ├── hiw-gibbon
│ │ │ ├── tree-and-array1.svg
│ │ │ ├── tree-and-array2.svg
│ │ │ └── tree-and-array3.svg
│ │ └── hourly-antenna
│ │ │ ├── antenna-page.jpg
│ │ │ ├── dockerhub-slack.jpg
│ │ │ └── drone-cron-setting.jpg
│ ├── 2020
│ │ └── antenna-with-gh-actions
│ │ │ ├── antenna-page-with-zenn.jpg
│ │ │ ├── antenna-page.jpg
│ │ │ └── pr.jpg
│ ├── 2021
│ │ ├── haskell-day-2021
│ │ │ └── ogp.png
│ │ └── symbols-in-ghc
│ │ │ └── hoogle.png
│ ├── about-bg.jpg
│ ├── background.png
│ ├── contact-bg.jpg
│ ├── home-bg.jpg
│ ├── logo-square.png
│ ├── logo-square.svg
│ ├── logo.png
│ ├── logo.svg
│ ├── post-bg.jpg
│ ├── post-sample-image.jpg
│ ├── slackarchive-io.png
│ └── subreddit-haskell_jp.png
├── index.html
├── js
│ ├── bootstrap.js
│ ├── bootstrap.min.js
│ ├── clean-blog.js
│ ├── jquery.js
│ └── jquery.min.js
├── posts
│ ├── 2017
│ │ ├── 01-first.md
│ │ ├── 02-haskell-on-heroku.md
│ │ ├── 03-haskell-antenna.md
│ │ ├── 04-slack-archive.md
│ │ ├── 05-subreddit.md
│ │ ├── 06-ghc-install.md
│ │ ├── 07-TypedHoles.md
│ │ ├── 08-ghc-4way-execution.md
│ │ ├── 09-ghc-users-guide.md
│ │ ├── 10-about-kind-system-part1.md
│ │ ├── 11-haskell-newbies-talks.md
│ │ ├── 12-ghc-show-info.md
│ │ ├── 13-about-kind-system-part2.md
│ │ ├── advent-calendar-2017.md
│ │ ├── no-stack-build.md
│ │ ├── typesafe-precure2.md
│ │ └── windows-gotchas.md
│ ├── 2018
│ │ ├── about-ghc-exts-1.md
│ │ ├── derive-json-no-prefix.md
│ │ ├── ghc-proposal-and-patch.md
│ │ ├── haskell-day-2018.md
│ │ ├── main-tester.md
│ │ ├── renew-haskell-antenna.md
│ │ ├── substring-parser.md
│ │ ├── super-precure-monad.md
│ │ ├── tech-book-fest-5.md
│ │ ├── topic-request.md
│ │ ├── unordered-containers-hash-dos.md
│ │ ├── windows-gotchas-en.md
│ │ └── windows-long-path.md
│ ├── 2019
│ │ ├── asterius.md
│ │ ├── fallible.md
│ │ ├── haskell-day-2019.md
│ │ ├── haskell-in-vrchat.md
│ │ ├── haskell-symposium.md
│ │ ├── hiw-copilot.md
│ │ ├── hiw-ghc-future.md
│ │ ├── hiw-ghc8.8.md
│ │ ├── hiw-gibbon.md
│ │ ├── hourly-antenna.md
│ │ ├── regex-applicative.md
│ │ ├── stack-ghc8.8.md
│ │ ├── string-gap-for-heredoc-like.md
│ │ ├── strip-ansi-escape.md
│ │ ├── tidalcycles-stack.md
│ │ └── unicode-show.md
│ ├── 2020
│ │ ├── antenna-with-gh-actions.md
│ │ ├── break-monad-law-with-writer.md
│ │ ├── haskell-casually-at-work.md
│ │ ├── how-to-use-type-newtype-data.md
│ │ ├── io-monad-and-sideeffect.md
│ │ ├── property-io.md
│ │ ├── revenge-of-hourly-antenna.md
│ │ └── strict-gotchas.md
│ ├── 2021
│ │ ├── haskell-day-2021.md
│ │ ├── symbols-in-ghc.md
│ │ └── text-mono-traversable.md
│ ├── 2022
│ │ └── disband_admins.md
│ ├── about_admins.md
│ ├── about_us.md
│ ├── grc.md
│ ├── links.md
│ └── template.md
└── templates
│ ├── default.html
│ ├── post-list.html
│ └── post.html
├── src
└── site.hs
├── stack.yaml
├── stack.yaml.lock
└── test
└── DocTest.hs
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | # Ref: https://mmhaskell.com/blog/2018/4/25/dockerizing-our-haskell-app
5 | docker:
6 | - image: haskell:9.0.2-slim
7 | steps:
8 | - run: apt update
9 | - run: apt install -y zip jq curl
10 | - run: stack upgrade
11 | - run: "echo 'tcp 6 TCP' > /etc/protocols"
12 | - run: "stack config --system-ghc set system-ghc --global true"
13 | - checkout
14 |
15 | - restore_cache:
16 | keys:
17 | - 'dependencies-{{ checksum "stack.yaml" }}-{{ checksum "haskell-jp-blog.cabal" }}'
18 | - 'dependencies-'
19 | - run: stack build --compiler=ghc-9.0.2 --no-terminal --only-dependencies
20 | - save_cache:
21 | key: 'dependencies-{{ checksum "stack.yaml" }}-{{ checksum "haskell-jp-blog.cabal" }}'
22 | paths:
23 | - ~/.stack/
24 | - .stack-work/
25 |
26 | - restore_cache:
27 | keys:
28 | - 'executable-{{ checksum "src/site.hs" }}'
29 | - 'executable-'
30 | - run: stack --compiler=ghc-9.0.2 --local-bin-path='.' --no-terminal install --pedantic
31 | - save_cache:
32 | key: 'executable-{{ checksum "src/site.hs" }}'
33 | paths:
34 | - ./site
35 |
36 | - run: ./site build
37 | - store_artifacts: { path: ./generated-site/ }
38 |
39 | - run: |
40 | if [ "$CIRCLE_BRANCH" != master ] ; then
41 | printenv |
42 | grep -E '^CIRCLE_|^HOME' | # Circle CIの環境変数を抽出して、preview botのサーバーにJSONとして渡す https://circleci.com/docs/2.0/env-vars/
43 | jq -c -s -R 'split("\n")
44 | | map (split("=")
45 | | select(.[0] != null)
46 | | {(.[0]): .[1:] | join("=")})
47 | | add' |
48 | curl -H 'Content-Type:application/json' -d @- \
49 | http://haskell-jp-blog-artifact.hask.moe/
50 | fi
51 | - persist_to_workspace:
52 | root: .
53 | paths:
54 | - ./generated-site
55 |
56 | deploy:
57 | docker:
58 | - image: haskell:9.0.2-slim
59 | steps:
60 | - checkout:
61 | path: ~/project
62 | - add-ssh-keys:
63 | fingerprints:
64 | - "9f:97:4e:99:72:c0:62:1d:db:9e:8e:ce:62:3f:0a:52"
65 | - run: apt update
66 | - run: apt install -y make ssh-client
67 | - attach_workspace:
68 | at: .
69 | - run: |
70 | git config --global user.email "ci@haskell.jp"
71 | git config --global user.name "Circle CI User"
72 | ssh-keyscan github.com >> ~/.ssh/known_hosts
73 | STACK_LOCAL_INSTALL_PATH=dummy make -W site -W dummy/site -e deploy
74 |
75 | workflows:
76 | version: 2
77 | build_and_deploy:
78 | jobs:
79 | - build
80 | - deploy:
81 | requires:
82 | - build
83 | filters:
84 | branches:
85 | only:
86 | - master
87 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/topic-request.md:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | cabal-dev
3 | *.o
4 | *.hi
5 | *.chi
6 | *.chs.h
7 | .virtualenv
8 | *.exe
9 | .hsenv
10 | .cabal-sandbox/
11 | cabal.sandbox.config
12 | cabal.config
13 |
14 | # hakyll generated files
15 | /.hakyll-cache
16 | /generated-site
17 |
18 | # stack
19 | .stack-work/
20 |
21 | *~
22 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # 記事を寄稿する方法
2 |
3 | Haskell-jp Blogの寄稿に興味を持っていただいてありがとうございます!
4 | 記事を寄稿していただける場合、下記の流れで行います。
5 |
6 | 1. 投稿したい人が、[preprocessed-site/posts/](https://github.com/haskell-jp/blog/tree/master/preprocessed-site/posts/)というディレクトリーに、Markdownで記事を書いて置いてください。
7 | - GitHubのアカウントをお持ちであれば、上記のリンク先にある、"Create new file"というボタンから追加できるはずです。
8 | - 記事の先頭に書く内容などは、同じディレクトリーにある、適当なほかの記事を参考にしてください。
9 | - 内部でPandocを使用しているので、[Pandocがサポートしている構文](http://pandoc.org/MANUAL.html#pandocs-markdown)であれば、すべて利用できます。
10 | 1. 作成した記事を含めたコミットで、Pull requestを送ってください。先ほどの"Create new file"というボタンからの導線に従えば、割と簡単にできるはずです。
11 | 1. [GitHubのHaskell-jp organization](https://github.com/haskell-jp)に所属する人などが、記事をレビューします。適宜対応してください。
12 | 1. 送ったPull requestがマージされると、CIが自動で記事を公開してくれます!
13 |
14 | # 記事のライセンスについて
15 |
16 | 原則として、次のルールが適用されます。
17 |
18 | - 寄稿者が執筆した記事の著作権は、**寄稿者のもの**となります。
19 | - その上で、寄稿者が執筆した記事に対しては、**「[クリエイティブ・コモンズ 表示 4.0 国際 ライセンス](https://creativecommons.org/licenses/by/4.0/)(通称CC-BY 4.0)」**が適用されます。
20 | - 従って、Haskell-jp Blogに公開される記事は、寄稿者以外の人が、寄稿者の名前を表示させた上で、自由に再配布したり、改変したりすることができるという点を、あらかじめご了承ください。
21 | - 詳細は[クリエイティブ・コモンズ 表示 4.0 国際 ライセンスの条文](https://creativecommons.org/licenses/by/4.0/legalcode.ja)をご覧ください。
22 | - ただし、寄稿者以外の人がGitHubのPull requestやIssue報告などを通じて寄稿者の記事を修正する場合、著作権は、**記事の著作者の同意の下、記事の寄稿者に委譲**するものとします。Pull requestを送った人や、Issueを報告した人のものとはなりません。
23 |
24 | もし記事のライセンスについて、何かしら特別な事情がある場合、GitHubのIssueを通じてご相談ください。例外的な対応も、適宜検討します。
25 |
26 | # 記事にして欲しい内容を提案する方法と注意点
27 |
28 | 記事の寄稿ではなく、記事にして欲しい内容を提案していただける場合は、[このリンク](https://github.com/haskell-jp/blog/issues/new?template=topic-request.md&labels=Topic+Request)より Issue を作成してください。
29 | Issue には、どのような記事を書いてほしいか書いてください。
30 | 例えば:
31 |
32 | - ○○パッケージの使い方やサンプルが知りたい
33 | - 数学用語と Haskell 用語の対応関係が知りたい
34 | - 少し古めの Haskell 本を読む上での注意点が知りたい
35 | - などなど
36 |
37 | **ただし、知見の持ち主が居ないかもしれませんし、誰かの負担になるものなので必ず記事になるとは限りません。**
38 | また、場合によっては既に記事があるため、既存の記事を薦められるかもしれません。
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 Haskell-jp
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included
12 | in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 | This project is forked from [arow-oss/blog](https://github.com/arow-oss/blog).
23 | Here is the original copyright notice for it.
24 |
25 | Copyright (c) 2017-2017 ARoW
26 |
27 | Permission is hereby granted, free of charge, to any person obtaining
28 | a copy of this software and associated documentation files (the
29 | "Software"), to deal in the Software without restriction, including
30 | without limitation the rights to use, copy, modify, merge, publish,
31 | distribute, sublicense, and/or sell copies of the Software, and to
32 | permit persons to whom the Software is furnished to do so, subject to
33 | the following conditions:
34 |
35 | The above copyright notice and this permission notice shall be included
36 | in all copies or substantial portions of the Software.
37 |
38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
39 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
41 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
42 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
43 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
44 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
45 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build clean deploy release site watch
2 | all: site
3 |
4 | #############
5 | # Variables #
6 | #############
7 |
8 | # Path to the directory that `stack` uses to install binaries locally.
9 | STACK_LOCAL_INSTALL_PATH ?= $(shell stack path --local-install-root)
10 |
11 | # Path to the `site` binary.
12 | SITE_PROG_PATH = $(STACK_LOCAL_INSTALL_PATH)/site
13 |
14 | # The current commit's git hash.
15 | GIT_HASH = $(shell git rev-parse --short HEAD)
16 |
17 | ################################
18 | ## Targets for specific files ##
19 | ################################
20 |
21 | # target for the `site` binary. This binary is used to actually create the
22 | # html files.
23 | $(SITE_PROG_PATH): src/site.hs
24 | @echo "Building..."
25 | @stack build
26 | @echo "Built."
27 |
28 | #####################
29 | ## General targets ##
30 | #####################
31 |
32 | # Build the `site` binary. The `site` binary is used to build the actual .html
33 | # files for the site.
34 | build: $(SITE_PROG_PATH)
35 |
36 | # Clean all generated files.
37 | clean:
38 | @echo "Cleaning..."
39 | -@stack exec -- site clean 2>/dev/null || true
40 | @rm -rf .hakyll-cache/ generated-site/
41 | @stack clean
42 | @echo "Clean."
43 |
44 | # Deploy the site.
45 | # Commit the generated-site directory to the gh-pages git branch.
46 | # The way this is done is pretty hacky, but it works.
47 | deploy: site
48 | # Make sure this temporary working directory is empty.
49 | # (TODO: Really we should be using a directory with a random filename,
50 | # generated with something like mktemp.)
51 | rm -rf /tmp/haskell-jp-blog-deploy/
52 | mkdir /tmp/haskell-jp-blog-deploy/
53 | # Copy the generated site to the temp directory.
54 | cp -r generated-site /tmp/haskell-jp-blog-deploy/
55 | # Checkout the gh-pages branch.
56 | ifdef GITHUB_TOKEN
57 | git remote set-url origin "https://${GITHUB_TOKEN}@github.com/haskell-jp/blog.git"
58 | git fetch origin gh-pages
59 | git checkout -b gh-pages FETCH_HEAD
60 | else
61 | git checkout -t origin/gh-pages
62 | endif
63 | # Remove the pages for the current site.
64 | git rm -r -f --ignore-unmatch *
65 | git status
66 | # Copy all of the generated site's files to the current directory.
67 | cp -r /tmp/haskell-jp-blog-deploy/generated-site/* ./
68 |
69 | # Disable Jekyll to serve files whose names begin with `_`.
70 | # https://help.github.com/articles/files-that-start-with-an-underscore-are-missing/
71 | touch ./.nojekyll
72 |
73 | # Add everything back. (A lot of files probably won't change, so, for
74 | # instance, they won't show up on 'git status' even though we just did 'git
75 | # rm -rf *'. A 'git rm -rf FILE' followed by 'git add FILE' is a noop if
76 | # the file hasn't changed.)
77 | git add -A .
78 | git status
79 | # Do the commit and push.
80 | @git diff --exit-code; \
81 | rc=$?; if [ $rc != 0 ] ; then \
82 | git commit -m "Release $(GIT_HASH) on `date`."; \
83 | git push -f origin gh-pages; \
84 | else \
85 | echo "Skip commit and push to gh-pages"; \
86 | fi
87 | ifndef GITHUB_TOKEN
88 | # Go back to master.
89 | git checkout master
90 | endif
91 | rm -rf /tmp/haskell-jp-blog-deploy
92 |
93 | # Alias for deploy.
94 | release: deploy
95 |
96 | # Generate the .html files for our blog.
97 | site: $(SITE_PROG_PATH)
98 | @# We don't actually need to use rebuild here, we could just use build.
99 | @# If this blog becomes really big and produces tons of pages, then switching
100 | @# to 'build' here (and adding an additional site-rebuild target) would be a
101 | @# good idea.
102 | stack exec -- site rebuild
103 |
104 | test:
105 | stack test
106 |
107 | # Run a test webserver on http://0.0.0.0:8000 serving up the content of our
108 | # blog. If the content changes, it is automatically rebuilt.
109 | watch: $(SITE_PROG_PATH)
110 | stack exec -- site watch --host 0.0.0.0
111 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [Haskell-jp Blog](https://haskell.jp/blog)
2 |
3 | [](http://travis-ci.org/haskell-jp/blog)
4 | [](https://opensource.org/licenses/MIT)
5 |
6 | このリポジトリーでは[Haskell-jp Blog](https://haskell.jp/blog)の記事や、記事の内容などについての問題を管理しています。
7 | 広くHaskellに関する記事や、読みたい記事のテーマを常に募集しています!
8 | 寄稿方法等は下記をご覧ください。
9 |
10 | # 記事を投稿したい場合
11 |
12 | Haskell-jp Blogの寄稿に興味を持っていただいてありがとうございます!
13 | 基本的には投稿する人は、**Markdownで記事を書いて、Pull requestを送るだけ**です!
14 | 「記事を書いてみたいけど、ネタがない...」という場合、[こちらの一覧](https://github.com/haskell-jp/blog/issues?q=is%3Aopen+is%3Aissue+label%3A%22Topic+Request%22)を覗いてみてください。あなたが書きたい話題があるかもしれません!
15 |
16 | 詳しい方法や、あなたが書いた記事に適用されるライセンスについては[CONTRIBUTING.md](./CONTRIBUTING.md)をご覧ください。
17 |
18 | # 「こんなテーマの記事を読みたい!」場合
19 |
20 | Haskell-jp Blogでは、「Haskellについて、こんなことを知りたい!」という記事のテーマも常に募集しています!
21 | すでに知りたいテーマが[こちら](https://github.com/haskell-jp/blog/issues?q=is%3Aopen+is%3Aissue+label%3A%22Topic+Request%22)に登録されていた場合、 :+1: を押して支援するのもいいでしょう!
22 | 詳細は[CONTRIBUTING.mdのこちらのセクション](CONTRIBUTING.md#%E8%A8%98%E4%BA%8B%E3%81%AB%E3%81%97%E3%81%A6%E6%AC%B2%E3%81%97%E3%81%84%E5%86%85%E5%AE%B9%E3%82%92%E6%8F%90%E6%A1%88%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%A8%E6%B3%A8%E6%84%8F%E7%82%B9)をご覧ください。
23 |
24 | # 記事の内容などについて、問題を報告したい場合
25 |
26 | その他、記事の内容や、ウェブサイトの構成などについての問題があった場合、[GitHubのissue](https://github.com/haskell-jp/blog/issues/new)でご連絡ください。
27 | なお、既存の記事を修正される場合、修正内容についての著作権は、原則として、記事を元の寄稿者のものとなるのでご注意ください。
28 | 詳細は、[CONTRIBUTING.mdのライセンスについての注記](./CONTRIBUTING.md#記事のライセンスについて)をご覧ください。
29 |
--------------------------------------------------------------------------------
/Setup.hs:
--------------------------------------------------------------------------------
1 | import Distribution.Simple
2 | main = defaultMain
3 |
--------------------------------------------------------------------------------
/examples/2019/hiw-copilot/.gitignore:
--------------------------------------------------------------------------------
1 | .stack-work/
2 | *~
3 | *.exe
4 | *.o
5 | *.hi
6 | *.c
7 | *.h
8 |
--------------------------------------------------------------------------------
/examples/2019/hiw-copilot/README.md:
--------------------------------------------------------------------------------
1 | # How to build
2 |
3 | ```
4 | stack build copilot
5 | stack exec ghc heater.hs
6 | ```
7 |
--------------------------------------------------------------------------------
/examples/2019/hiw-copilot/heater.hs:
--------------------------------------------------------------------------------
1 | {-
2 | This example is copied from https://copilot-language.github.io/
3 |
4 | (c) 2009 Frank Dedden, Nis Nordby Wegmann, Lee Pike, Robin Morisset, Sebastian Niller, Alwyn Goodloe
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions
8 | are met:
9 |
10 | Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 |
13 | Redistributions in binary form must reproduce the above copyright
14 | notice, this list of conditions and the following disclaimer in the
15 | documentation and/or other materials provided with the distribution.
16 |
17 | Neither the name of the developers nor the names of its contributors
18 | may be used to endorse or promote products derived from this software
19 | without specific prior written permission.
20 |
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 | -}
33 |
34 | -- This is a simple example with basic usage. It implements a simple home
35 | -- heating system: It heats when temp gets too low, and stops when it is high
36 | -- enough. It read temperature as a byte (range -50C to 100C) and translates
37 | -- this to Celcius.
38 |
39 | import Language.Copilot
40 | import Copilot.Compile.C99
41 |
42 | import Prelude hiding ((>), (<), div)
43 |
44 | -- External temperature as a byte, range of -50C to 100C
45 | temp :: Stream Word8
46 | temp = extern "temperature" Nothing
47 |
48 | -- Calculate temperature in Celcius.
49 | -- We need to cast the Word8 to a Float. Note that it is an unsafeCast, as there
50 | -- is no direct relation between Word8 and Float.
51 | ctemp :: Stream Float
52 | ctemp = (unsafeCast temp) * (150.0 / 255.0) - 50.0
53 |
54 | spec = do
55 | -- Triggers that fire when the ctemp is too low or too high,
56 | -- pass the current ctemp as an argument.
57 | trigger "heaton" (ctemp < 18.0) [arg ctemp]
58 | trigger "heatoff" (ctemp > 21.0) [arg ctemp]
59 |
60 | -- Compile the spec
61 | main = reify spec >>= compile "heater"
62 |
--------------------------------------------------------------------------------
/examples/2019/hiw-copilot/stack.yaml:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by 'stack init'
2 | #
3 | # Some commonly used options have been documented as comments in this file.
4 | # For advanced use and comprehensive documentation of the format, please see:
5 | # https://docs.haskellstack.org/en/stable/yaml_configuration/
6 |
7 | # Resolver to choose a 'specific' stackage snapshot or a compiler version.
8 | # A snapshot resolver dictates the compiler version and the set of packages
9 | # to be used for project dependencies. For example:
10 | #
11 | # resolver: lts-3.5
12 | # resolver: nightly-2015-09-21
13 | # resolver: ghc-7.10.2
14 | #
15 | # The location of a snapshot can be provided as a file or url. Stack assumes
16 | # a snapshot provided as a file might change, whereas a url resource does not.
17 | #
18 | # resolver: ./custom-snapshot.yaml
19 | # resolver: https://example.com/snapshots/2018-01-01.yaml
20 | resolver: lts-14.6
21 |
22 | # User packages to be built.
23 | # Various formats can be used as shown in the example below.
24 | #
25 | # packages:
26 | # - some-directory
27 | # - https://example.com/foo/bar/baz-0.0.2.tar.gz
28 | # subdirs:
29 | # - auto-update
30 | # - wai
31 | packages: []
32 | # Dependency packages to be pulled from upstream that are not in the resolver.
33 | # These entries can reference officially published versions as well as
34 | # forks / in-progress versions pinned to a git hash. For example:
35 | #
36 | # extra-deps:
37 | # - acme-missiles-0.3
38 | # - git: https://github.com/commercialhaskell/stack.git
39 | # commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
40 | #
41 | extra-deps:
42 | - copilot-3.0.1
43 | - copilot-c99-3.0.2@sha256:e84e435eeb7eb0e8e69a016aae5a18c07980cb7caa4d049c29d21d96bf55df91,2274
44 | - copilot-core-3.0.1@sha256:cd5f4d47fba9e717b274cf393a86c8d60103c009c694f570746401f085b14426,2121
45 | - copilot-language-3.0.1@sha256:581c6cc1205b8e5022e1afee54149de0c84a4c31f9e8412aab947d1a979075db,2937
46 | - copilot-libraries-3.0@sha256:e085b7f1ff3f8a0cb307c03ffffbe930e1eeabdf962d07431b8b74f6e8d434de,1966
47 | - copilot-theorem-3.0@sha256:a04e72748753e279f17f814c953100490ddfd65c7860b29b72b0c18f8f3955ef,4225
48 | - bimap-0.3.3@sha256:232518c0410990665b9c8677eb9318ee355c001d58945ddcbedec3baa30b4160,1475
49 | - language-c99-0.1.1@sha256:c06430bfa5b52cefc8cce142ea9a1e52b2900f5d84408d6b198ddcdb1c5bff0a,1587
50 | - language-c99-simple-0.1.2@sha256:5b522616fa22a0909250d56a0632f1f1cae1c38d585149e13eeb809103af9543,1540
51 | - language-c99-util-0.1.1@sha256:480adee2ba3045d04305be5362be991b1814faf58cfd7af1f845d0fc9dbcf3a7,1177
52 |
53 | # Override default flag values for local packages and extra-deps
54 | # flags: {}
55 |
56 | # Extra package databases containing global packages
57 | # extra-package-dbs: []
58 |
59 | # Control whether we use the GHC we find on the path
60 | # system-ghc: true
61 | #
62 | # Require a specific version of stack, using version ranges
63 | # require-stack-version: -any # Default
64 | # require-stack-version: ">=2.1"
65 | #
66 | # Override the architecture used by stack, especially useful on Windows
67 | # arch: i386
68 | # arch: x86_64
69 | #
70 | # Extra directories used by stack for building
71 | # extra-include-dirs: [/path/to/dir]
72 | # extra-lib-dirs: [/path/to/dir]
73 | #
74 | # Allow a newer minor version of GHC than the snapshot specifies
75 | # compiler-check: newer-minor
76 |
--------------------------------------------------------------------------------
/examples/2019/hiw-copilot/stack.yaml.lock:
--------------------------------------------------------------------------------
1 | # This file was autogenerated by Stack.
2 | # You should not edit this file by hand.
3 | # For more information, please see the documentation at:
4 | # https://docs.haskellstack.org/en/stable/lock_files
5 |
6 | packages:
7 | - completed:
8 | hackage: copilot-3.0.1@sha256:7faa685324a3a3b0f1b2ba1638ba2c99a9c2887105af9f0b9f14b3236c22a44f,2040
9 | pantry-tree:
10 | size: 568
11 | sha256: 80ee00b549a78aec160b62a30e543a3366b80fa6e6501a8c2487f99b993daa62
12 | original:
13 | hackage: copilot-3.0.1
14 | - completed:
15 | hackage: copilot-c99-3.0.2@sha256:e84e435eeb7eb0e8e69a016aae5a18c07980cb7caa4d049c29d21d96bf55df91,2274
16 | pantry-tree:
17 | size: 644
18 | sha256: 71f79a08fadf3aae2bab3a807c7ad63167319014bc8c5bf586cde49fe5ca4344
19 | original:
20 | hackage: copilot-c99-3.0.2@sha256:e84e435eeb7eb0e8e69a016aae5a18c07980cb7caa4d049c29d21d96bf55df91,2274
21 | - completed:
22 | hackage: copilot-core-3.0.1@sha256:cd5f4d47fba9e717b274cf393a86c8d60103c009c694f570746401f085b14426,2121
23 | pantry-tree:
24 | size: 1882
25 | sha256: f68e6f0f28a7ae705799cf37feadf237fa3d3c258fb0e53b7792a665e9e328b0
26 | original:
27 | hackage: copilot-core-3.0.1@sha256:cd5f4d47fba9e717b274cf393a86c8d60103c009c694f570746401f085b14426,2121
28 | - completed:
29 | hackage: copilot-language-3.0.1@sha256:581c6cc1205b8e5022e1afee54149de0c84a4c31f9e8412aab947d1a979075db,2937
30 | pantry-tree:
31 | size: 2181
32 | sha256: 3bb29b06dc89d2e41da34e2945044e080938ef19c21740e8846dca02ff7d9ca4
33 | original:
34 | hackage: copilot-language-3.0.1@sha256:581c6cc1205b8e5022e1afee54149de0c84a4c31f9e8412aab947d1a979075db,2937
35 | - completed:
36 | hackage: copilot-libraries-3.0@sha256:e085b7f1ff3f8a0cb307c03ffffbe930e1eeabdf962d07431b8b74f6e8d434de,1966
37 | pantry-tree:
38 | size: 909
39 | sha256: f7cbae21502cccbdc7214b86095d52b78eb479f8c16902cfa987dff0b6dcde16
40 | original:
41 | hackage: copilot-libraries-3.0@sha256:e085b7f1ff3f8a0cb307c03ffffbe930e1eeabdf962d07431b8b74f6e8d434de,1966
42 | - completed:
43 | hackage: copilot-theorem-3.0@sha256:a04e72748753e279f17f814c953100490ddfd65c7860b29b72b0c18f8f3955ef,4225
44 | pantry-tree:
45 | size: 2624
46 | sha256: 630999d9ee57e73a0e6babcd0cf3df93ffda748220ab0d7f81f7fa4ef27ecb20
47 | original:
48 | hackage: copilot-theorem-3.0@sha256:a04e72748753e279f17f814c953100490ddfd65c7860b29b72b0c18f8f3955ef,4225
49 | - completed:
50 | hackage: bimap-0.3.3@sha256:232518c0410990665b9c8677eb9318ee355c001d58945ddcbedec3baa30b4160,1475
51 | pantry-tree:
52 | size: 414
53 | sha256: 5c7485014c2f342d215ace99cd06361f7607169aebe8d4aca2f265fa5c3c6761
54 | original:
55 | hackage: bimap-0.3.3@sha256:232518c0410990665b9c8677eb9318ee355c001d58945ddcbedec3baa30b4160,1475
56 | - completed:
57 | hackage: language-c99-0.1.1@sha256:c06430bfa5b52cefc8cce142ea9a1e52b2900f5d84408d6b198ddcdb1c5bff0a,1587
58 | pantry-tree:
59 | size: 399
60 | sha256: de3e5af62744508f8271c053ad2c598b6819e6fafeece4e3b5d27cf71e0d3a59
61 | original:
62 | hackage: language-c99-0.1.1@sha256:c06430bfa5b52cefc8cce142ea9a1e52b2900f5d84408d6b198ddcdb1c5bff0a,1587
63 | - completed:
64 | hackage: language-c99-simple-0.1.2@sha256:5b522616fa22a0909250d56a0632f1f1cae1c38d585149e13eeb809103af9543,1540
65 | pantry-tree:
66 | size: 574
67 | sha256: 1d297b46c78e2a498f7828bddc794d8355656273f7334f8ab27452ccfd28d5be
68 | original:
69 | hackage: language-c99-simple-0.1.2@sha256:5b522616fa22a0909250d56a0632f1f1cae1c38d585149e13eeb809103af9543,1540
70 | - completed:
71 | hackage: language-c99-util-0.1.1@sha256:480adee2ba3045d04305be5362be991b1814faf58cfd7af1f845d0fc9dbcf3a7,1177
72 | pantry-tree:
73 | size: 489
74 | sha256: 3a5e1387e9b073dad4f51fa749fd4c33e2abe31566b63a120a38a7f88d809493
75 | original:
76 | hackage: language-c99-util-0.1.1@sha256:480adee2ba3045d04305be5362be991b1814faf58cfd7af1f845d0fc9dbcf3a7,1177
77 | snapshots:
78 | - completed:
79 | size: 524127
80 | url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/14/6.yaml
81 | sha256: dc70dfb45e2c32f54719819bd055f46855dd4b3bd2e58b9f3f38729a2d553fbb
82 | original: lts-14.6
83 |
--------------------------------------------------------------------------------
/examples/2020/strict-gotchas/README.md:
--------------------------------------------------------------------------------
1 | # haskell-jp-blog-example-strict-gotchas
2 |
3 | [こちらのIssue](https://github.com/haskell-jp/blog/issues/167)について、せっかく盛り上がってきたので少しでも進めようと、まずはサンプルを書いてみることにしました。
4 |
5 | ## 注記
6 |
7 | - 記事の内容と大きく連動しそうなので、敢えて同じリポジトリーに上げています。
8 | - 各 `*.hs ` ファイルを `runghc --ghc-arg=-XStrict` で実行した場合と `--ghc-arg=-XStrict` なしで実行した場合とで比較することで、挙動の違いを体験できるように作っています。
9 |
--------------------------------------------------------------------------------
/examples/2020/strict-gotchas/const.hs:
--------------------------------------------------------------------------------
1 | dontReferArgs :: a -> b -> a
2 | dontReferArgs = const
3 |
4 | referArgs :: a -> b -> a
5 | referArgs x _ = x
6 |
7 | main :: IO ()
8 | main = do
9 | print $ dontReferArgs "dontReferArgs" (undefined :: Int)
10 | print $ referArgs "referArgs" (undefined :: Int)
11 |
--------------------------------------------------------------------------------
/examples/2020/strict-gotchas/stack.yaml:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by 'stack init'
2 | #
3 | # Some commonly used options have been documented as comments in this file.
4 | # For advanced use and comprehensive documentation of the format, please see:
5 | # https://docs.haskellstack.org/en/stable/yaml_configuration/
6 |
7 | # Resolver to choose a 'specific' stackage snapshot or a compiler version.
8 | # A snapshot resolver dictates the compiler version and the set of packages
9 | # to be used for project dependencies. For example:
10 | #
11 | # resolver: lts-3.5
12 | # resolver: nightly-2015-09-21
13 | # resolver: ghc-7.10.2
14 | #
15 | # The location of a snapshot can be provided as a file or url. Stack assumes
16 | # a snapshot provided as a file might change, whereas a url resource does not.
17 | #
18 | # resolver: ./custom-snapshot.yaml
19 | # resolver: https://example.com/snapshots/2018-01-01.yaml
20 | resolver: ghc-8.10.1
21 |
22 | # User packages to be built.
23 | # Various formats can be used as shown in the example below.
24 | #
25 | # packages:
26 | # - some-directory
27 | # - https://example.com/foo/bar/baz-0.0.2.tar.gz
28 | # subdirs:
29 | # - auto-update
30 | # - wai
31 | packages: []
32 | # Dependency packages to be pulled from upstream that are not in the resolver.
33 | # These entries can reference officially published versions as well as
34 | # forks / in-progress versions pinned to a git hash. For example:
35 | #
36 | # extra-deps:
37 | # - acme-missiles-0.3
38 | # - git: https://github.com/commercialhaskell/stack.git
39 | # commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
40 | #
41 | # extra-deps: []
42 |
43 | # Override default flag values for local packages and extra-deps
44 | # flags: {}
45 |
46 | # Extra package databases containing global packages
47 | # extra-package-dbs: []
48 |
49 | # Control whether we use the GHC we find on the path
50 | # system-ghc: true
51 | #
52 | # Require a specific version of stack, using version ranges
53 | # require-stack-version: -any # Default
54 | # require-stack-version: ">=2.1"
55 | #
56 | # Override the architecture used by stack, especially useful on Windows
57 | # arch: i386
58 | # arch: x86_64
59 | #
60 | # Extra directories used by stack for building
61 | # extra-include-dirs: [/path/to/dir]
62 | # extra-lib-dirs: [/path/to/dir]
63 | #
64 | # Allow a newer minor version of GHC than the snapshot specifies
65 | # compiler-check: newer-minor
66 |
--------------------------------------------------------------------------------
/examples/2020/strict-gotchas/stack.yaml.lock:
--------------------------------------------------------------------------------
1 | # This file was autogenerated by Stack.
2 | # You should not edit this file by hand.
3 | # For more information, please see the documentation at:
4 | # https://docs.haskellstack.org/en/stable/lock_files
5 |
6 | packages: []
7 | snapshots: []
8 |
--------------------------------------------------------------------------------
/examples/2020/strict-gotchas/stackoverflow-foldr.hs:
--------------------------------------------------------------------------------
1 | {-
2 | GHCRTS=-K100k stack exec runghc -- ./stackoverflow-foldr.hs
3 | GHCRTS=-K100k stack exec runghc -- --ghc-arg=-XStrict ./stackoverflow-foldr.hs
4 | -}
5 |
6 | import Control.Exception
7 | import Data.List
8 |
9 | main :: IO ()
10 | main = do
11 | let size = 5000
12 |
13 | evaluate . length $ foldr (:) [] [1 .. size]
14 | putStrLn "DONE: foldr 1"
15 |
16 | evaluate . length $ foldr (\x z -> x : z) [] [1 .. size]
17 | putStrLn "DONE: foldr 2"
18 |
--------------------------------------------------------------------------------
/examples/2020/strict-gotchas/storable.hs:
--------------------------------------------------------------------------------
1 | {-# LANGUAGE ScopedTypeVariables #-}
2 |
3 | import Foreign.Marshal.Alloc
4 | import Foreign.Ptr
5 | import Foreign.Storable
6 |
7 | data Test = Test Int Int deriving Show
8 |
9 | instance Storable Test where
10 | sizeOf _ = sizeOf (1 :: Int) * 2
11 | alignment _ = 8
12 | peek = error "This should not be called in this program"
13 | poke = error "This should not be called in this program"
14 |
15 | main :: IO ()
16 | main = alloca $ \(_ :: Ptr Test) -> putStrLn "This won't be printed when Strict is enabled"
17 |
--------------------------------------------------------------------------------
/examples/2020/strict-gotchas/where.hs:
--------------------------------------------------------------------------------
1 | -- Originally created by @pxfnc
2 | -- https://qiita.com/pxfnc/items/a26bda6d11402daba675
3 |
4 | -- Compare
5 | -- runghc where.hs
6 | -- And
7 | -- runghc --ghc-arg=-XStrict where.hs
8 |
9 |
10 | main :: IO ()
11 | main = print $ div10 0
12 |
13 | div10 :: Int -> Int
14 | div10 n
15 | | n == 0 = 0
16 | | otherwise = result
17 | where
18 | result = 10 `div` n
19 |
--------------------------------------------------------------------------------
/haskell-jp-blog.cabal:
--------------------------------------------------------------------------------
1 | name: haskell-jp-blog
2 | version: 0.1.0.0
3 | build-type: Simple
4 | cabal-version: >= 1.10
5 | license: MIT
6 | license-file: LICENSE
7 |
8 | executable site
9 | hs-source-dirs: src
10 | main-is: site.hs
11 | build-depends: base == 4.*
12 | , containers >= 0.5
13 | , data-default >= 0.5
14 | , hakyll
15 | , pandoc-types
16 | , skylighting
17 | , text
18 | , filepath
19 | ghc-options: -threaded -Wall
20 | default-language: Haskell2010
21 |
22 | test-suite site-doctest
23 | type: exitcode-stdio-1.0
24 | main-is: DocTest.hs
25 | hs-source-dirs: test
26 | build-depends: base
27 | , doctest
28 | , Glob
29 | default-language: Haskell2010
30 | ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
31 |
--------------------------------------------------------------------------------
/preprocessed-site/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs: {}
3 | workflows:
4 | version: 2
5 |
--------------------------------------------------------------------------------
/preprocessed-site/README.md:
--------------------------------------------------------------------------------
1 | # [Start Bootstrap](http://startbootstrap.com/) - [Clean Blog](http://startbootstrap.com/template-overviews/clean-blog/)
2 |
3 | [Clean Blog](http://startbootstrap.com/template-overviews/clean-blog/) is a stylish, responsive blog theme for [Bootstrap](http://getbootstrap.com/) created by [Start Bootstrap](http://startbootstrap.com/). This theme features a blog homepage, about page, contact page, and an example post page along with a working PHP contact form.
4 |
5 | ## Getting Started
6 |
7 | To use this theme, choose one of the following options to get started:
8 | * Download the latest release on Start Bootstrap
9 | * Fork this repository on GitHub
10 |
11 | ## Bugs and Issues
12 |
13 | Have a bug or an issue with this theme? [Open a new issue](https://github.com/IronSummitMedia/startbootstrap-clean-blog/issues) here on GitHub or leave a comment on the [template overview page at Start Bootstrap](http://startbootstrap.com/template-overviews/clean-blog/).
14 |
15 | ## Creator
16 |
17 | Start Bootstrap was created by and is maintained by **David Miller**, Managing Parter at [Iron Summit Media Strategies](http://www.ironsummitmedia.com/).
18 |
19 | * https://twitter.com/davidmillerskt
20 | * https://github.com/davidtmiller
21 |
22 | Start Bootstrap is based on the [Bootstrap](http://getbootstrap.com/) framework created by [Mark Otto](https://twitter.com/mdo) and [Jacob Thorton](https://twitter.com/fat).
23 |
24 | ## Copyright and License
25 |
26 | Copyright 2013-2015 Iron Summit Media Strategies, LLC. Code released under the [Apache 2.0](https://github.com/IronSummitMedia/startbootstrap-clean-blog/blob/gh-pages/LICENSE) license.
--------------------------------------------------------------------------------
/preprocessed-site/css/style.css:
--------------------------------------------------------------------------------
1 | .notice {
2 | font-size: 70%;
3 | margin-top: 0.5em;
4 | }
5 |
6 | span.author {
7 | margin-right: 1em;
8 | }
9 |
10 | span.meta {
11 | margin: 1em;
12 | }
13 |
14 | .hash-target {
15 | margin-bottom: 1em;
16 | }
17 | .hash-target:target {
18 | background-color: #FFFCA7;
19 | border-color: #FDE14F;
20 | border-width: 1px;
21 | border-style: solid;
22 | border-radius: 1px;
23 | }
24 |
25 | #md-post-content table tr {
26 | border-top: 1px solid #cccccc;
27 | }
28 |
29 | #md-post-content table th,
30 | #md-post-content table td {
31 | border: 1px solid #cccccc;
32 | padding: 6px 13px;
33 | }
34 |
35 | #md-post-content img {
36 | max-width:100%;
37 | height: auto;
38 | }
39 |
40 | ul.social-buttons {
41 | list-style: none;
42 | vertical-align: middle;
43 | padding: 5px;
44 | }
45 | ul.social-buttons li {
46 | display: inline-block;
47 | vertical-align: middle;
48 | }
49 |
50 | .navbar {
51 | background-color: #F3C677;
52 | border-color: #080808;
53 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
54 | font-size: 14px;
55 | }
56 |
57 | .navbar-brand > img {
58 | width: 150px;
59 | position: relative;
60 | bottom: 30%;
61 | }
62 |
63 | .navbar .navbar-nav > li > a {
64 | color: #777;
65 | font-weight: bold;
66 | text-decoration: none;
67 | }
68 |
69 | .navbar .navbar-nav > li > a:focus,
70 | .navbar .navbar-nav > li > a:hover {
71 | color: #000;
72 | }
73 |
74 | #post-navigation {
75 | display: flex;
76 | align-items: center;
77 | }
78 |
79 | #post-navigation div {
80 | display: flex;
81 | align-items: center;
82 | }
83 |
84 | #post-navigation a {
85 | color: #313537;
86 | font-size: smaller;
87 | }
88 |
89 | :target {
90 | margin-top: -60px;
91 | padding-top: 60px;
92 | }
93 |
94 | #table-of-contents-outer {
95 | margin-bottom: 4ex;
96 | }
97 |
98 | #table-of-contents {
99 | display: inline-block;
100 | border: 1px solid #ccc;
101 | border-radius: 4px;
102 | background-color: #f5f5f5;
103 | margin-left: 5%;
104 | margin-right: 10%;
105 | padding: 0.5em 1em;
106 | font-size: 80%;
107 | }
108 |
109 | #table-of-contents .table-of-contents-title {
110 | font: normal x-large serif;
111 | margin-bottom: 1ex;
112 | }
113 |
114 | #table-of-contents a {
115 | font-family: sans;
116 | text-decoration: none;
117 | }
118 |
119 | #table-of-contents a:hover {
120 | text-decoration: underline;
121 | }
122 |
123 | #table-of-contents ul {
124 | padding-left: 1em;
125 | }
126 |
127 | #table-of-contents code {
128 | color: black;
129 | background-color: transparent;
130 | }
131 |
132 | span.link-to-here-outer {
133 | display: inline-block;
134 | font: bold 8pt sans;
135 | vertical-align: middle;
136 | width: 50pt;
137 | margin-left: -50pt;
138 | }
139 |
140 | .link-to-here-outer a {
141 | text-decoration: none;
142 | color: white;
143 | }
144 |
145 | span.link-to-here {
146 | display: inline-block;
147 | visibility: hidden;
148 | padding: 5pt;
149 | background-color: #606060;
150 | vertical-align: middle;
151 | }
152 |
153 | span.link-to-here-outer:hover a .link-to-here {
154 | visibility: visible;
155 | }
156 |
157 | /*
158 | * Overwrite bootstrap styles for skylighting
159 | */
160 | div.sourceCode {
161 | background-color: #f5f5f5;
162 | border: 1px solid #ccc;
163 | border-radius: 4px;
164 | }
165 |
166 | pre.sourceCode {
167 | background-color: unset;
168 | border: unset;
169 | border-radius: unset;
170 | }
171 |
172 | .jumbotron {
173 | color: #333;
174 | }
175 |
176 | .btn {
177 | border-radius: 4px;
178 | }
179 |
--------------------------------------------------------------------------------
/preprocessed-site/feed.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskell-jp Blog
3 | description: 日本Haskellユーザーグループ公式ブログ
4 | author: Haskell-jp
5 | email: ""
6 | root: https://haskell.jp/blog
7 | ---
8 |
--------------------------------------------------------------------------------
/preprocessed-site/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/preprocessed-site/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/preprocessed-site/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/preprocessed-site/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/preprocessed-site/img/2017/12-rts-coverage1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2017/12-rts-coverage1.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2017/12-rts-coverage2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2017/12-rts-coverage2.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2017/12-rts-space-profile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2017/12-rts-space-profile.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2017/12-rts-threadscope.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2017/12-rts-threadscope.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2017/13-01-kind-graph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2017/13-01-kind-graph.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/_DSC1173.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/_DSC1173.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/_DSC1176.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/_DSC1176.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/_DSC1177.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/_DSC1177.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/_DSC1178.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/_DSC1178.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/_DSC1179.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/_DSC1179.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/_DSC1183.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/_DSC1183.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/_DSC1186.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/_DSC1186.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/_DSC1191.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/_DSC1191.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/_DSC1193.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/_DSC1193.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/_DSC1194.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/_DSC1194.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/aiya000.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/aiya000.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/connpass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/connpass.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/fumieval.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/fumieval.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/khibino.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/khibino.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/lotz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/lotz.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/questionnaire1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/questionnaire1.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/haskell-day-2018/questionnaire2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/haskell-day-2018/questionnaire2.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2018/tech-book-fest-5-banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2018/tech-book-fest-5-banner.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/fallible/slack.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/fallible/slack.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/after-party.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/after-party.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/aiya000.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/aiya000.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/egison.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/egison.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/ekmett.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/ekmett.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/fumieval.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/fumieval.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/lotz.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/lotz.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/matsubara0507.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/matsubara0507.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/mr_konn.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/mr_konn.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/nobsun.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/nobsun.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/question1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/question1.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/question2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/question2.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/question3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/question3.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/question4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/question4.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/question5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/question5.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/question6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/question6.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-day-2019/y_taka_23.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-day-2019/y_taka_23.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-in-vrchat/vrc-lt-control-panel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-in-vrchat/vrc-lt-control-panel.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-in-vrchat/vrc-lt-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-in-vrchat/vrc-lt-image.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-in-vrchat/vrc-lt-room.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-in-vrchat/vrc-lt-room.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/haskell-in-vrchat/vrc-lt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/haskell-in-vrchat/vrc-lt.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/hiw-gibbon/tree-and-array1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/hiw-gibbon/tree-and-array2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/hiw-gibbon/tree-and-array3.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/hourly-antenna/antenna-page.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/hourly-antenna/antenna-page.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/hourly-antenna/dockerhub-slack.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/hourly-antenna/dockerhub-slack.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2019/hourly-antenna/drone-cron-setting.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2019/hourly-antenna/drone-cron-setting.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2020/antenna-with-gh-actions/antenna-page-with-zenn.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2020/antenna-with-gh-actions/antenna-page-with-zenn.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2020/antenna-with-gh-actions/antenna-page.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2020/antenna-with-gh-actions/antenna-page.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2020/antenna-with-gh-actions/pr.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2020/antenna-with-gh-actions/pr.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/2021/haskell-day-2021/ogp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2021/haskell-day-2021/ogp.png
--------------------------------------------------------------------------------
/preprocessed-site/img/2021/symbols-in-ghc/hoogle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/2021/symbols-in-ghc/hoogle.png
--------------------------------------------------------------------------------
/preprocessed-site/img/about-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/about-bg.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/background.png
--------------------------------------------------------------------------------
/preprocessed-site/img/contact-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/contact-bg.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/home-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/home-bg.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/logo-square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/logo-square.png
--------------------------------------------------------------------------------
/preprocessed-site/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/logo.png
--------------------------------------------------------------------------------
/preprocessed-site/img/post-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/post-bg.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/post-sample-image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/post-sample-image.jpg
--------------------------------------------------------------------------------
/preprocessed-site/img/slackarchive-io.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/slackarchive-io.png
--------------------------------------------------------------------------------
/preprocessed-site/img/subreddit-haskell_jp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haskell-jp/blog/330766de16f08f9dfa006cf86280a8b4df71e14e/preprocessed-site/img/subreddit-haskell_jp.png
--------------------------------------------------------------------------------
/preprocessed-site/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskell-jp Blog
3 | author: Haskell-jp
4 | headingBackgroundImage: ./img/background.png
5 | headingDivClass: site-heading
6 | heading: Haskell-jp Blog
7 | subHeadingContent:
8 | 日本Haskellユーザーグループ公式ブログ
9 | description: 日本Haskellユーザーグループ公式ブログ
10 | year: 2017 - 2019
11 | ---
12 |
13 |
14 |
15 | $partial("templates/post-list.html")$
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2017/01-first.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 日本Haskellユーザーグループ発足・Slackチーム開放のお知らせ
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: もくもく会を添えて
6 | author: Haskell-jp
7 | tags: Haskell-jp
8 | date: April 30, 2017
9 | ...
10 | ---
11 |
12 | はじめまして。Haskell-jpこと日本Haskellユーザーグループです!
13 | この度、日本におけるHaskellの普及を目指して、ユーザーグループを立ち上げることといたしました。
14 | 詳しいことは「[日本Haskellユーザーグループについて](../about_us.html)」をご覧いただくとして、立ち上げにともない、3点発表です!
15 |
16 | # その1 公式Slackチームの開放
17 |
18 | Haskell-jp立ち上げ前、有志による議論に使用していたSlackチームを開放します!
19 | 下記から登録してください!
20 |
21 | [https://haskell.jp/signin-slack.html](https://haskell.jp/signin-slack.html)
22 |
23 | 現時点の運用ルールは、以下のとおりです。
24 |
25 | - **#questions**や**#beginners**では**Haskellに関する質問を募集**します!
26 | - 質問に対する回答は、**スレッド機能を使って回答**しましょう。複数の質問を同時に投稿しやすくするための配慮です。
27 | - その他、「[GRC](https://github.com/haskell-jp/community/blob/master/GRC.md)」を守り、参加者のみなさんが不快になるような行動は避けてください。
28 | - 追記: 発言を[slack-log](https://github.com/haskell-jp/slack-log/)というツールを通して、**当Slackチームに所属しない人にも保存・公開**することにいたしました。あらかじめご容赦ください。
29 | - 保存した発言は で閲覧できます。
30 |
31 | # その2 Haskellもくもく会 -> Haskell-jpもくもく会!
32 |
33 | Haskell-jp発起人の一人である@igrepが主催していた「[Haskellもくもく会](https://haskellmokumoku.connpass.com)」を、「[Haskell-jpもくもく会](https://haskell-jp.connpass.com)」、すなわちわれわれ日本Haskellユーザーグループの活動の一部として再出発させます!
34 | といっても、実態は今まで通りです。会場もやることもハッシュタグも特に変わりありません。
35 | これからもよろしくお願いします!
36 |
37 | # その3 blog記事を募集します!
38 |
39 | Haskell-jpはHaskellを普及させる(多くの人に使ってもらう)ためのグループであり、主役はHaskellユーザーのみなさんです。
40 | そこで、Haskellユーザーのみなさんがより効果的にHaskellを広められるよう、**当blogで掲載する記事の寄稿**を募集します!
41 |
42 | 募集する記事のテーマは次のとおりです。
43 |
44 | - 日本人が作ったHaskell製(ライブラリー|アプリケーション)の紹介
45 | - Haskellを(仕事で|趣味で)使ってみた
46 | - Haskellに関するイベント情報
47 | - 英語など外国語で書かれたHaskell情報の翻訳
48 | - Haskellに対する熱い思い
49 | - MastodonクローンをHaskellで作ってみたよ、とか!
50 | - その他、Haskellに関することならなんでも!
51 |
52 | 応募していただける場合、[こちらのリポジトリー](https://github.com/haskell-jp/blog)にPull Requestを送ってください。
53 | `preprocessed-site/posts`というディレクトリー以下に新しいmarkdownファイルを追加していただく形になります。
54 | [こちらの記事のテンプレート](https://github.com/haskell-jp/blog/blob/master/preprocessed-site/posts/template.md)も参考にしてください。
55 | なにか気になる点があれば[Slackチームの#haskell-jp-blogチャンネル](https://haskell-jp.slack.com/messages/C52C84YF3/)までお気軽にどうぞ!
56 | (2017年9月30日修正: チャンネル名を実態に合わせて修正しました)
57 |
58 | 早速最初の記事として、@arowmさんに「[Dockerを使ってHaskellアプリをHerokuにデプロイする](02-haskell-on-heroku.html)」という記事をいただきました!ありがとうございます!
59 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2017/03-haskell-antenna.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskell Antenna を公開しました
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | author: Tatsuya Hirose
6 | date: May 21, 2017
7 | tags: Haskell-jp
8 | ...
9 | ---
10 |
11 | Haskellは学習コストが高いと言われることがよくあります。その理由の一つにWeb上でHaskellの情報を探しても情報源になかなかたどり着けないと云う問題があると思います。日本語の情報となるとなおさら難しくなるでしょう。
12 |
13 | [Haskell Antenna](https://haskell.jp/antenna/)はその問題の解決に一石を投じるために作ったサービスです。Haskellに関する最新情報はQiitaやスタックオーバーフローといったCGMやHaskellの情報を中心に発信している個人ブログから見ることが出来ます。Antennaはそういった情報源を一箇所に並べることで、Haskellユーザーが日本語で発信している最新情報に、簡単にアクセスできるようにします。今はAPIをHerokuで運用しているため起動に時間がかかることがありますのでご容赦下さい。
14 |
15 | Antennaでは配信する情報源(RSS)をいつでも募集しています。もし追加すべき情報源にアイデアがあれば[GitHubレポジトリのREADME](https://github.com/haskell-jp/antenna#フィードの追加方法)にかかれている方法を参考にPull Requestを送っていただくことが可能ですし[Slackの#antenna](https://haskell-jp.slack.com/messages/C5BAM1SJW/)を通じて提案を行ってもらうことも大歓迎です。Haskellの情報を中心に発信しているブログを持っている方は是非 追加提案をしていただけると助かります。
16 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2017/04-slack-archive.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: SlackArchiveを導入しました
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: 発言が1万件を越えて保存・公開されるようになります!
6 | author: Haskell-jp
7 | tags: Haskell-jp
8 | date: May 25, 2017
9 | ...
10 | ---
11 |
12 | すでにSlackチームに所属している皆さんにはお伝えしたとおりですが、[Haskell-jpのSlackチーム](https://haskell-jp.slack.com/)に、[SlackArchive](http://slackarchive.io/)というサービスを導入しました!
13 | [こちら](https://haskell-jp.slackarchive.io/)からアーカイブを閲覧できます!
14 |
15 | 
16 |
17 | # SlackArchiveって?
18 |
19 | [こちらのTechCrunchの記事](http://jp.techcrunch.com/2015/12/01/20151130slackarchive-gives-you-public-chat-archive-for-free/)のとおりですが、Slackでの発言を(Slackの無料枠の1万件を超えて)保存し、Slackチームに所属していない人が閲覧したり、Googleなどで検索したりできるようにしてくれるサービスです。
20 | 我々のように、ベターメーリングリストとしてSlackチームを活用しているチームにぴったりですね!
21 |
22 | # と、いうわけで
23 |
24 | 残念ながら現状SlackArchiveの無料プランを利用しているので、SlackArchive使用開始後の発言のみですが、今後は我々の情報共有が、貴重な資産としてネットの海に残されるようになるはずです。
25 | 今後もネチケットを守って楽しいHaskell-jpライフを! 🙇
26 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2017/05-subreddit.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskell-jp 公式subreddit作成のお知らせ
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: 今後は質問や議論はr/haskell_jpで行うのを推奨します。
6 | author: Haskell-jp
7 | tags: Haskell-jp
8 | date: June 18, 2017
9 | ...
10 | ---
11 |
12 | # [r/haskell\_jp](https://www.reddit.com/r/haskell_jp/)ができました!
13 |
14 | みなさん、[Reddit](https://www.reddit.com)というWebサービスをご存知でしょうか?
15 | [Wikipedia曰く](https://en.wikipedia.org/wiki/Reddit)Redditは、世界の**Webサイト全体で9番目**に多い利用者数を誇る、巨大フォーラムサービスです。WebサイトのURLや様々な話題をスレッドとして投稿し、コメントを付けたり評価したりすることで、毎日盛んな議論が行われています。
16 |
17 | 詳しい使い方などについては「[Redditの歩き方](https://chikawatanabe.com/2014/11/17/reddit-2/)」というウェブサイトが参考になります。
18 |
19 | 今回、我々Haskell-jpでは、dfordivamさんの提案を受け、Reddit上でHaskellについて日本語で投稿したりコメントできるスペース、[r/haskell\_jp](https://www.reddit.com/r/haskell_jp/)を作成いたしました!
20 |
21 | 
22 |
23 | 今後はSlackよりもこちらに、Haskellに関するお悩み相談や、見つけた(パッケージ|ブログ記事|アプリケーション)を共有していただけると幸いです。
24 |
25 | ## 作った動機
26 |
27 | [SlackArchiveのこの辺り](https://haskell-jp.slackarchive.io/general/page-2)からさかのぼって、**dfordivam**さんという方の発言を探していただけるとわかるのですが、RedditはSlackよりも**オープンで、人気が高く、より議論に向いた**プラットフォームです。
28 | 当然SlackArchiveよりGoogle検索にも引っかかりやすいので、質問やお悩み相談とその回答、見つけたWebサイトの共有などは、Redditを利用したほうがアクセスしてもらいやすいだろう、と考えたためです。
29 |
30 | ## 今後について: Slackとの使い分けは?
31 |
32 | さて、これまで[Haskell-jpのSlack](https://haskell.jp/signin-slack.html)では[questionsチャンネル](https://haskell-jp.slackarchive.io/questions/)を中心に、Haskellに関する数々の質問や相談が、短い期間ながら行われてきました。[randomチャンネル](https://haskell-jp.slackarchive.io/random/)などでのウェブサイトの共有もたくさんありました。
33 | 今後は、[Haskell-jpのsubreddit](https://www.reddit.com/r/haskell_jp/)でお悩み相談や議論を行うとして、Slackチームはどうなってしまうのでしょうか?
34 |
35 | ざっくり結論から申しますと、「好きな方を使え」というのが公式の見解です。
36 | Slackはもともとの日本における人気の高さも手伝い、Haskell-jpでもすでに十分に定着しました。Redditにはないemojiによるreaction機能などもあるので、こちらのほうがよい、と言う人も数多くいるでしょう。
37 | もちろん、カジュアルな話題(例えば「自分をHaskellの型に例えるなら」とか)ではSlackのほうが敷居が低くてよいでしょう。
38 |
39 | まとめると、以下のようなガイドラインとなります。
40 |
41 | - Haskellに関するお悩み相談や、発見したHaskellに関するWebページ(パッケージやHaskell製アプリケーション、ブログ記事など)は、**どちらかというと**[Haskell-jpのsubreddit](https://www.reddit.com/r/haskell_jp/)に、
42 | - それ以外の、ゆるいHaskellの話題はSlackに投稿していただけると幸いです。
43 | - 前項にかかわらず、Slackに慣れているから、Slackのemoji reactionのほうが楽しいから、といった場合はSlackをご利用ください。
44 | - ちなみに、もちろんteratailやStackOverflowでの質問もよいでしょう。本日から、Slackの[questions-feedチャンネル](https://haskell-jp.slack.com/messages/C5UPKRGRE/convo/C4M4TT8JJ-1497217764.308002/)に質問が流れるようになりました!
45 |
46 | 以上、今後も[Slackチーム](https://haskell.jp/signin-slack.html)、[r/haskell\_jp](https://www.reddit.com/r/haskell_jp/)ともどもよろしくお願いします!
47 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2017/06-ghc-install.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 素のGHCをローカルディレクトリにインストールする方法
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | author: takenbu.hs
6 | date: August 8, 2017
7 | ...
8 | ---
9 |
10 | # はじめに
11 |
12 | 素(単独)のGHCのバイナリをローカルディレクトリにインストールする方法について簡単に紹介します。
13 | GHCの新リリースが出た場合などに、stack や haskell-platform 経由ではなく、手軽にインストールして遊べます。
14 | 以下、Linux系での手順です。 ユーザー権限で行えます。
15 |
16 |
17 | # インストール方法
18 |
19 | ## 1. リリース物をdownloadします
20 |
21 | GHC単独品の配布ディレクトリ( https://www.haskell.org/ghc/ )から、目的のバージョンのGHCを選びます。
22 |
23 | 例えば、Linux(Debian, Ubuntu, ...)用の ghc 8.2.1 のバイナリであれば、以下から、`ghc-8.2.1-x86_64-deb8-linux.tar.xz` を選びます。
24 |
25 | https://www.haskell.org/ghc/download_ghc_8_2_1.html#linux_x86_64
26 |
27 |
28 | ## 2. tarファイルを展開します
29 |
30 | ```sh
31 | $ tar -xvJf ghc-8.2.1-x86_64-deb8-linux.tar.xz
32 | ```
33 |
34 | ## 3. インストール先のローカルディレクトリを作ります
35 |
36 | ```sh
37 | $ mkdir ghc821
38 | ```
39 |
40 | ## 4. configします
41 |
42 | tarを展開したトップディレクトリにcdで移動します。
43 | さらに、`--prefix`オプションで、GHCのインストール先のディレクトリを指定します。
44 |
45 | ```sh
46 | $ cd ghc-8.2.1
47 | $ ./configure --prefix=/home/my/ghc821
48 | ```
49 |
50 | ## 5. installします
51 |
52 | tarを展開したトップディレクトリで、makeコマンドを実行します。
53 | ```sh
54 | $ make install
55 | ```
56 |
57 | これで、`--prefix` オプションで指定したディレクトリの `bin/`下に、`ghc`, `ghci`, `runghc` などがインストールされます。
58 | なお、インストール後は、tarで展開した側のディレクトリ以下は削除して構いません。
59 |
60 | ## 6. 遊ぶ
61 |
62 | `bin/`ディレクトリ下の、`ghc`, `ghci`, `runghc` などで遊べます。 例えば、以下のようにしてghciを起動できます。
63 |
64 | ```
65 | $ ghc821/bin/ghci
66 | GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
67 | Prelude> 1+2
68 | 3
69 | ```
70 |
71 | ghc8.2.1のカラフルなエラーメッセージや、compact-regionなど、新機能を手軽に楽しめます、enjoy! :)
72 |
73 | もちろん、環境変数PATHにインストール先のディレクトリを追加しておけば、デフォルトでこのGHCを使用できます。
74 |
75 |
76 | # 補足
77 |
78 | ## 補足1
79 |
80 | 本格的にGHCでprojectを作る場合には、素のGHCでなく、stack や haskell-platform をインストールするのが良いでしょう。
81 |
82 | * [stack](https://haskell-lang.org/get-started)
83 | * [haskell-platform](https://www.haskell.org/platform/)
84 |
85 |
86 | ## 補足2
87 |
88 | 環境によっては、libgmpが無いというエラーが発生する場合があります。
89 | その場合は、以下の対処方法があります。
90 | ```
91 | # apt-get install libgmp10
92 | # cd /usr/lib/x86_64-linux-gnu
93 | # ln -s libgmp.so.10 libgmp.so
94 | ```
95 |
96 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2017/07-TypedHoles.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: GHCのTyped Holes機能で、式中の部分の型を推論させる
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | author: takenbu.hs
6 | date: August 8, 2017
7 | ...
8 | ---
9 |
10 | 最近はあまり話題になってないかもしれませんが、 `Typed holes` 機能についての紹介です。
11 |
12 | ghc7.8くらいの頃に導入された機能で、ソースコードの式の中に `_` か `_` で始まる識別名を書くと、その部分の型を推論してくれます。
13 |
14 | ### 使い方
15 |
16 | 例えば、
17 |
18 | ```Haskell
19 | main = print $ 1.0 + _
20 | ```
21 | のようなコードを書いて、 `runghc`や`ghci`や`ghc`で実行すると、 `_` 部の型をエラーメッセージで教えてくれます。
22 |
23 |
24 | ### エラーメッセージの表示例
25 |
26 | 例えば、以下のようにエラーメッセージが表示されます。 以下の例では、`_`部が、`Double`型であることを示しています。
27 |
28 | ```Haskell
29 | $ runghc test1.hs
30 |
31 | test1.hs:3:22: error:
32 | • Found hole: _ :: Double
33 | • In the second argument of ‘(+)’, namely ‘_’
34 | In the second argument of ‘($)’, namely ‘1.0 + _’
35 | In the expression: print $ 1.0 + _
36 | • Relevant bindings include main :: IO () (bound at test1.hs:3:1)
37 | |
38 | 3 | main = print $ 1.0 + _
39 | | ^
40 |
41 | ```
42 |
43 |
44 | ### 補足1
45 |
46 | `_` の替りに、 `_hoge` のように名前付けしても構いません。
47 |
48 | ghci で、 `:t` で型を調べるのと同じように気軽に使えます。 (最近はIDEがサポートしていて、明示的には使わなかったりするかもしれません。)
49 |
50 |
51 | ### 補足2
52 |
53 | 詳細情報は以下にあります。
54 |
55 | *
56 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2017/08-ghc-4way-execution.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: GHCの4つの実行方法
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: コンパイル実行、スクリプト的実行、対話的実行、ワンライナー的実行
6 | author: takenbu.hs
7 | date: August 13, 2017
8 | ...
9 | ---
10 |
11 | ## はじめに
12 |
13 | Haskell用コンパイラであるGHCには、以下のように4種類の実行方法があります。
14 |
15 | * コンパイル実行 : `ghc`
16 | * スクリプト的実行 : `runghc` (or `runhaskell`)
17 | * 対話的実行 : `ghci`
18 | * ワンライナー的実行 : `ghc -e`
19 |
20 | 以下、それぞれについて簡単に紹介します。
21 | なお、本記事では、stack経由ではなく、素のGHCを使う場合について説明しています。
22 |
23 |
24 | ## コンパイル実行
25 |
26 | Haskellのソースファイルから、実行ファイルを生成(コンパイル)する方法です。生成された実行ファイルは、ユーザーが明示的に起動することにより実行されます。
27 |
28 | 例えばソースファイルが以下の場合に、
29 | ```
30 | $ cat prog.hs
31 |
32 | main = print $ 1 + 2
33 | ```
34 |
35 | 以下の様に、`ghc`コマンドを使ってコンパイルを実行できます。
36 | ```
37 | $ ghc prog.hs
38 | [1 of 1] Compiling Main ( prog.hs, prog.o )
39 | Linking prog ...
40 | ```
41 |
42 | これにより、実行ファイル(prog)と中間ファイル(prog.hi, prog.o)が生成されます。
43 | ```
44 | $ ls
45 | prog prog.hi prog.hs prog.o
46 | ```
47 |
48 | 生成された実行ファイル(prog)は、ユーザーが明示的に指定して起動します。
49 | ```
50 | $ ./prog
51 | 3
52 | ```
53 |
54 | `ghc`のコンパイル方法についての詳しい説明は、[こちら](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using.html)や[こちら](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/flags.html)にあります。
55 | なお、stackを使用する場合は、`ghc`コマンドではなく、`stack ghc`コマンドによりコンパイルを実行できます。
56 |
57 |
58 |
59 | ## スクリプト的実行
60 |
61 | Haskellのソースファイルから、実行ファイルを一時的に生成(コンパイル)し、その実行ファイルを起動する方法です。つまり、スクリプト的な実行方法です。
62 | 例えば以下の様に、`runghc`コマンド(または別名である`runhaskell`コマンド)により実行できます。
63 | ```
64 | $ runghc prog.hs
65 | 3
66 | ```
67 |
68 | `runghc`の使用方法についての詳しい説明は、[こちら](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/runghc.html)にあります。
69 | なお、stackを使用する場合は、`runghc`コマンドではなく、`stack runghc`コマンドにより実行できます。
70 |
71 |
72 |
73 | ## 対話的実行
74 |
75 | Haskellのソースを対話的に入力する実行方法です。いわゆる、REPL(read-eval-print-loop)と呼ばれるものです。
76 | 例えば以下の様に、`ghci`コマンドにより実行できます。
77 | ```
78 | $ ghci
79 | GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
80 |
81 | Prelude> 1+2
82 | 3
83 |
84 | Prelude> :q
85 | Leaving GHCi.
86 | ```
87 |
88 | `ghci`の使用方法についての詳しい説明は、[こちら](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html)にあります。
89 | なお、stackを使用する場合は、`ghci`コマンドではなく、`stack ghci`コマンドにより実行できます。
90 |
91 |
92 |
93 | ## ワンライナー的実行
94 |
95 | コマンドライン上で、Haskellの「式」を直接入力する実行方法です。1つの式だけを指定できます。
96 | 例えば以下の様に、`-e`オプション付きの`ghc -e`コマンドにより実行できます。
97 |
98 | ```
99 | $ ghc -e "1+2"
100 | 3
101 | ```
102 |
103 | `ghc -e`の使用方法についての説明は、[こちら](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using.html#expression-evaluation-mode)にあります。
104 | なお、stackを使用する場合は、`ghc -e`コマンドではなく、`stack ghc -- -e`コマンドにより実行できます。
105 |
106 |
107 |
108 | ## おまけ
109 |
110 | 以下は、`ghc -e`による実行例です。
111 | 少し特殊かもしれない記法も記載していますので、以下は気軽に読み飛ばしてください。
112 |
113 | 例えば、このようにして数列を手軽に生成できます。
114 | ```
115 | $ ghc -e '[1..10]'
116 | [1,2,3,4,5,6,7,8,9,10]
117 | ```
118 |
119 | リスト内包表記も使えます。
120 | ```
121 | $ ghc -e '[x^2 | x <- [1..10]]'
122 | [1,4,9,16,25,36,49,64,81,100]
123 | ```
124 |
125 | 1行毎に出力することもできます。
126 | ```
127 | $ ghc -e 'mapM_ print [1..3]'
128 | 1
129 | 2
130 | 3
131 | ```
132 |
133 | 入力系の関数も使えます。
134 | ```
135 | $ ghc -e 'getLine'
136 | ABC
137 | "ABC"
138 | ```
139 |
140 | 入力だけでなく出力系の関数も使えます。
141 | ```
142 | $ ghc -e 'getLine >>= putStrLn'
143 | ABC
144 | ABC
145 | ```
146 |
147 | do記法も使えます。
148 | ```
149 | $ ghc -e 'do {x <- getLine; putStrLn x}'
150 | ABC
151 | ABC
152 | ```
153 |
154 | 入出力のフィルタコマンドも表現できます。
155 | ```
156 | $ ghc -e 'interact $ unlines . map ("hello " ++) . lines'
157 | John
158 | hello John
159 | Mike
160 | hello Mike
161 | ```
162 |
163 |
164 | ペア形式のデータも簡単に生成できます。
165 | ```
166 | $ ghc -e "zip [1..3] ['A'..]"
167 | [(1,'A'),(2,'B'),(3,'C')]
168 | ```
169 |
170 | 組み合わせのデータも簡単に生成できます。
171 | ```
172 | $ ghc -e "(,) <$> [1..3] <*> ['A'..'C']"
173 | [(1,'A'),(1,'B'),(1,'C'),(2,'A'),(2,'B'),(2,'C'),(3,'A'),(3,'B'),(3,'C')]
174 | ```
175 |
176 | 組み合わせを連結したデータでも生成できます。
177 | ```
178 | $ ghc -e '(++) <$> ["R", "G", "B"] <*> map show [0..3]'
179 | ["R0","R1","R2","R3","G0","G1","G2","G3","B0","B1","B2","B3"]
180 | ```
181 |
182 | ちょっと込み入ったデータも生成できます。
183 | ```
184 | $ ghc -e '(\x y -> x ++ "-" ++ y) <$> ["2016", "2017", "2018"] <*> ["Jan", "Feb", "Mar"]'
185 | ["2016-Jan","2016-Feb","2016-Mar","2017-Jan","2017-Feb","2017-Mar","2018-Jan","2018-Feb","2018-Mar"]
186 | ```
187 |
188 | 実は ghc -eコマンドでは、ghciのコマンドも使えます。 ですので、型を調べる`:t`(:type)コマンドを使って型の情報を表示させることもできます。
189 | ```
190 | $ ghc -e ':t foldl'
191 | foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
192 | ```
193 |
194 | GHC8.2以降であれば、上の例のような一般化された型での表示ではなく、デフォルトの型を考慮してシンプルに表示する`:t +d`コマンドも使えます。(詳細は[こちら](https://downloads.haskell.org/%7Eghc/latest/docs/html/users_guide/ghci.html#ghci-cmd-:type%20+d))
195 | ```
196 | $ ghc -e ':t +d foldl'
197 | foldl :: (b -> a -> b) -> b -> [a] -> b
198 | ```
199 |
200 | 名前の情報を表示する`:i`(:info)コマンドも使えます。
201 | ```
202 | $ ghc -e ':i foldl'
203 | class Foldable (t :: * -> *) where
204 | ...
205 | foldl :: (b -> a -> b) -> b -> t a -> b
206 | ...
207 | -- Defined in ‘Data.Foldable’
208 | ```
209 |
210 | カインド(種)を表示する`:k`(:kind)コマンドも使えます。
211 | ```
212 | $ ghc -e ':k Maybe'
213 | Maybe :: * -> *
214 | ```
215 |
216 | Bashなどのシェル環境であれば、シェル変数を使った準クォートも使えます!
217 | ```
218 | $ NUM=5
219 | $ ghc -e "[1..$NUM]"
220 | [1,2,3,4,5]
221 | ```
222 |
223 | シェル側から簡単にデータを渡せます。
224 | ```
225 | $ X1="[1..3]"
226 | $ X2="['A'..'C']"
227 | $ ghc -e "zip $X1 $X2"
228 | [(1,'A'),(2,'B'),(3,'C')]
229 | ```
230 |
231 |
232 | interact関数でなく、getContents関数でも入力できます。
233 | ```
234 | $ cat test.dat # data file for example
235 | 1
236 | 2
237 | 3
238 |
239 | $ cat test.dat | ghc -e "lines <$> getContents"
240 | ["1","2","3"]
241 | ```
242 |
243 | 入力列に対する累算も容易です。
244 | ```
245 | $ cat test.dat | ghc -e "(sum . map read .lines) <$> getContents"
246 | 6
247 | ```
248 |
249 | 少し記述が長いですが、数値データとして処理させることも出来ます。
250 | ```
251 | $ cat test.dat | ghc -e 'interact $ unlines . map (show . (*2) . (read::String -> Int)) . lines'
252 | 2
253 | 4
254 | 6
255 | ```
256 |
257 | let式も使えます。
258 | ```
259 | $ ghc -e "let x = 1; y = 2 in x+y"
260 | 3
261 | ```
262 |
263 | 階層指定により特定モジュールの関数を指定することも出来ます。
264 | ```
265 | $ ghc -e 'Text.Printf.printf "%s %d\n" "abc" 1'
266 | abc 1
267 | ```
268 |
269 | `.ghci`ファイルをカレントディレクトリかホームディレクトリに配置しておけば、実行前に読み込めます。
270 | ```
271 | $ cat .ghci
272 | import Text.Printf
273 |
274 | $ ghc -e 'printf "%s %d\n" "abc" 1'
275 | abc
276 | ```
277 |
278 | 数学関数も使えます。
279 | ```
280 | $ ghc -e "sin (pi/2)"
281 | 1.0
282 | ```
283 |
284 | 数学関数とリスト内包表記の併用も便利です。
285 | ```
286 | $ ghc -e "[sin (n * pi/8) | n <- [0..4]]"
287 | [0.0,0.3826834323650898,0.7071067811865475,0.9238795325112867,1.0]
288 | ```
289 |
290 | リスト的な処理は、やはり簡単です。
291 | ```
292 | $ ghc -e 'replicate 5 "hello"'
293 | ["hello","hello","hello","hello","hello"]
294 | ```
295 |
296 | 以上です、enjoy!
297 |
298 |
299 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2017/09-ghc-users-guide.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: GHCのユーザーズガイドへのリンク集
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: コンパイル時オプション、実行時オプション、対話コマンド、言語拡張など
6 | author: takenbu.hs
7 | date: August 14, 2017
8 | ...
9 | ---
10 |
11 | ## はじめに
12 |
13 | Haskell用コンパイラであるGHCのユーザーズガイド(マニュアル)の在り処について紹介します。
14 | また、GHCのユーザーズガイドはボリュームが多いため、頻繁に調べる項目を見つけやすいように、いくつかの章や節の在り処を簡単に紹介します。
15 |
16 |
17 |
18 | ## ユーザーズガイドの在り処
19 |
20 | GHCの最新版のユーザーズガイド(英語版)は以下にあります。
21 |
22 | * [`Glasgow Haskell Compiler User's Guide: Web版`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/)
23 | * [`Glasgow Haskell Compiler User's Guide: PDF版`](https://downloads.haskell.org/~ghc/latest/docs/users_guide.pdf)
24 |
25 |
26 | なお、素晴らしい日本語翻訳版が以下にあります。
27 |
28 | * [GHC 8.0](https://ghcguide.haskell.jp/users_guide/index.html) (nobsunさん訳; 翻訳中)
29 | * [GHC 7.8](http://www.kotha.net/ghcguide_ja/7.8.2/) (kothaさん訳)
30 |
31 |
32 |
33 | ## ユーザーズガイド内で、よく調べる項目の在り処
34 |
35 | GHCのユーザーズガイドはボリュームが多いため、頻繁に調べる項目を見つけやすいように、いくつかの章や節を以下に紹介します。
36 |
37 | * [GHCのコンパイル時オプション(フラグ)一覧](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/flags.html)
38 | * [GHCの実行時オプション(フラグ)](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/runtime_control.html#setting-rts-options)
39 | * [GHCのプロファイラのオプション](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/profiling.html#profiling)
40 | * [GHCiのコマンド](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html#ghci-commands)
41 | * [runghcのフラグ](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/runghc.html#runghc-flags)
42 | * [GHCの言語拡張](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#language-options)
43 | * [GHCのプラグマ](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#pragmas)
44 | * [ghc-pkgのコマンド(オプション)](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/packages.html#using-packages)
45 |
46 |
47 |
48 | ## 補足1
49 |
50 | ### ユーザーズガイド内の検索について
51 |
52 | ユーザーズガイドのWeb画面右側の"Quick search"の検索ボックスにより、ユーザーズガイド内の検索が可能です。
53 |
54 |
55 | ### ユーザーズガイドのソースの在り処について
56 |
57 | * ユーザーズガイドのソースは、[こちら](https://github.com/ghc/ghc/tree/master/docs/users_guide)にあります。
58 | * ユーザーズガイドの記述方法やビルド方法についての説明は、[こちら](https://ghc.haskell.org/trac/ghc/wiki/Commentary/UserManual)にあります。
59 |
60 |
61 |
62 | ## 補足2
63 |
64 | 参考までに、GHCではなく、Haskell言語仕様の方も以下に紹介します。
65 |
66 | * [Haskell 2010 Language Report; Web版](https://www.haskell.org/onlinereport/haskell2010/)
67 | * [Haskell 2010 Language Report; PDF版](https://www.haskell.org/definition/haskell2010.pdf)
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2017/11-haskell-newbies-talks.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskell-jp現在の活動・目的総ざらい
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: Haskell入門者LT会での発表内容の再共有です
6 | author: Yuji Yamamoto
7 | postedBy: Yuji Yamamoto(@igrep)
8 | date: August 30, 2017
9 | ...
10 | ---
11 |
12 | # Haskell入門者LT会で発表してきました
13 |
14 | 昨日、私山本悠滋は[Haskell入門者LT会 - connpass](https://shinjukuhs.connpass.com/event/58936/)で、ゲストとして参加し、我らがHaskell-jpの宣伝をして参りました。
15 |
16 | 発表資料自体は[こちらのSlideshareのページ](https://www.slideshare.net/igrep/haskelljp-haskelljp)に載せたのですが、残念ながら貼り付けているリンクがすべて無効になってしまいました。
17 | 本資料は、Haskell-jpの現在進行中の活動や、今後の目標などを伝えると同時に、そのリンク集としての意味合いが強いので、これでは致命的です。
18 |
19 | そこで、本記事ではスライドの内容のうち、Haskell-jpの現在の活動や今後についての箇所をほぼそのまま貼り付けて再共有することにいたします。
20 | この機会に何かしらの活動に興味を持っていただければ幸いです。
21 |
22 | ↓以下がその内容となります。
23 | markdownで書いといてよかった! (⌒\_⌒)
24 |
25 | # 目的
26 |
27 | - 日本にHaskellを普及させる
28 | - 日本を代表するHaskellのユーザーグループとなる
29 | - 国内外のHaskellコミュニティーをはじめ、IT業界における広い認知を得ること
30 |
31 | # [Slackチーム](https://haskell-jp.slackarchive.io/)
32 |
33 | - いろいろしゃべったり質問したり、フィードを流したりしてます
34 | - リンク先は[SlackArchive](http://slackarchive.io/)を利用した発言ログ
35 | - 登録は[こちら](https://haskell.jp/signin-slack.html)から。
36 |
37 | ## 運用ルール
38 |
39 | - 質問は\#questionsか\#generalで。
40 | - \#generalで質問を許可しているのは、慌ててやってきた人が質問した場合の救済策
41 | - たらい回しにするやりとりを避けたい
42 | - ネチケット(多分死語)は守りましょう。
43 | - チャンネル作りはご自由に。
44 |
45 | ## おすすめチャンネル
46 |
47 | - questions: 軽い気持ちの質問チャンネル
48 | - questions-feed: teratail・Stackoverflowなどの質問が流れます
49 | - ちょっと更新頻度が高すぎるかもですが...。
50 | - event-announcement: イベントの募集やどこそこで登壇する、といった情報を配信
51 | - 自動化したい...。
52 |
53 | # [Reddit](https://www.reddit.com/r/haskell_jp/)
54 |
55 | ## 作った背景:
56 |
57 | - Slackだとクローズドで、生み出した情報とかが再利用できないよね。
58 | - 検索にもひっかからないし、
59 | - SlackArchiveは微妙だし。
60 |
61 | ## 特徴
62 |
63 | - スレッドがDISQUSみたいなツリー上の構造になることもあり、込み入った議論や相談に便利。
64 | - もちろん検索エンジンもインデックスしてくれる。
65 | - 実は**今はSlackよりこちらを推奨**しています。
66 | - Slackチームのreddit-haskell-jpのチャンネルにも投稿が流れます。
67 |
68 | # [Haskell-jpブログ](https://haskell.jp/blog/)
69 |
70 | - 〆(゚\_゚\*)
71 | 広くHaskellに関する記事なら誰でも投稿できる。
72 | - **執筆者常時募集**。
73 | - [こちらのリポジトリー](https://github.com/haskell-jp/blog)にPull requestを送ってください。
74 | - このイベントのレポートなんてこれまでなかったタイプの記事なんでちょうどいいでしょう!
75 |
76 | # [Haskell-jpもくもく会](https://haskell-jp.connpass.com/)
77 |
78 | - (\*´Д\`)
79 | 「Haskellに関する作業をもくもくとやったり、希望者でLTを行ったりするゆるい会」
80 | - 弊ユーザーグループ設立のきっかけとなった[Haskellもくもく会](https://haskellmokumoku.connpass.com/)が前身。
81 | - Haskellもくもく会から数えて次回で46回目!
82 | - 初心者から上級者まで好き勝手やっております。
83 | - 重要: [次回は9月10日(日)](https://haskell-jp.connpass.com/event/64567/)
84 | - (;\^ω\^)
85 | 学生枠を設けてますが、今回に限って学生枠が集まりすぎてうれしい悲鳴を上げています。
86 |
87 | # [Haskell-jp wiki](https://wiki.haskell.jp/)
88 |
89 | - いろいろ書いているWikiです!
90 | - [gitit](https://github.com/jgm/gitit)というHaskell製のWikiエンジンでできています。
91 | - GitHubアカウントがあれば誰でも編集できます。
92 |
93 | ## おすすめのページ:
94 |
95 | - [Haskellに関する日本語のリンク集](https://wiki.haskell.jp/Links)
96 | - [データ構造列伝](https://wiki.haskell.jp/%E3%83%87%E3%83%BC%E3%82%BF%E6%A7%8B%E9%80%A0%E5%88%97%E4%BC%9D)
97 |
98 | # [Haskell-jp TODOリスト](https://trello.com/b/GfAyczPt/haskell-jp)
99 |
100 | - パブリックなTrelloのボード。
101 | - Haskell-jpのやりたいことが割と見えます。
102 | - 要望がある場合Slackなどで提案すると、多分優しい誰かがBacklogに追加してくれます。
103 | - 現状、権限を持った人以外コメント含め書き込みはできません。あしからず。
104 | - 希望者は私なりSlackなりでご相談を。
105 |
106 | # [Haskellレシピ集](https://github.com/haskell-jp/recipe-collection)
107 |
108 | - 文字通りレシピ集
109 | - あまり私は関わっていないのですが、どうも更新停止気味 (◞‸◟)
110 |
111 | # [Haskell Antenna](https://haskell.jp/antenna/)
112 |
113 | - [Haskell News](http://haskellnews.org/)にインスパイアされて作成。
114 | - 超実験的。**運がよかったら見える**。
115 | - 作者の[\@lotz84氏](https://github.com/lotz84)個人のHerokuアカウント(無料枠)で動いているので...。
116 | - [こちらのリポジトリー](https://github.com/haskell-jp/antenna)にPull requestを送れば情報源を増やすこともできます。
117 |
118 | # [相互リンク集](https://haskell.jp/blog/posts/links.html)
119 |
120 | - Haskell好きな人が、
121 | - Haskellについて書いたWebサイトに、
122 | - (サイト全体の一部でOK)
123 | - こんなバナー→
を張ってもらい、
124 | - それを一覧にしたもの
125 |
126 | # そのほか、特にやる気はあること
127 |
128 | ## 入門コンテンツ
129 |
130 | - 鋭意開発中。まだ共有してなくてすまん。
131 | - 今後ブログと並ぶ大きなコンテンツの一つとしたい。
132 |
133 | ## 法人化
134 |
135 | - 「Haskell-jp」としてはゆるめのつながりでありたい
136 | - でも、運営委員会的な組織は多分遅かれ速かれ必要
137 | - お金の管理とか、目標とか責任とかを明確にするため
138 |
139 | # まとめ
140 |
141 | - Haskell-jpの一つの大きな役目は、haskell.jpというドメインを通じ、場を提供すること
142 | - ブログとか、アンテナとか、Wikiとか。
143 | - haskell.jpを利用したコンテンツはほかにもあっていいと思うのでどんどんどうぞ!
144 | - 何かあればRedditやSlack、GitHubのIssueなどでご連絡ください!
145 | - 今後とも、Haskell-jpをよろしくお願いします hask(\_ \_)eller
146 |
147 | 以上が発表内容です。
148 | いかがでしょうか?気になる活動があればぜひぜひ参加してみてください!
149 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2017/no-stack-build.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskell-jp Blogへの投稿が簡単になりました!
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: Advent Calendarの記事の投稿も募集しております!
6 | author: Haskell-jp
7 | tags: Haskell-jp, CircleCI, Travis CI
8 | date: November 27, 2017
9 | ...
10 | ---
11 |
12 | こんにちは。Haskell-jpです。
13 | ちょっと間が空いてしまいましたが、久々の投稿です。Haskell自体の話と関係なくてすみません!
14 |
15 | 内容としてはタイトルのとおりなのですが、[こちら](https://github.com/haskell-jp/blog/pull/51)や[こちら](https://github.com/haskell-jp/blog/pull/53)をはじめとするPull requestにより、当ブログの記事の投稿が簡単になりました!
16 | 具体的には、下記の点を改善しております。
17 |
18 | - 記事を作成してPull requestを送った際、\[Merge pull request\]ボタンを押してmasterブランチにマージしただけで自動で記事が公開されるようになりました!
19 | - [CircleCIのartifacts機能](https://circleci.com/docs/1.0/build-artifacts/)を利用することにより、ビルド結果から実際に公開される際のページをプレビューできるようにしました!
20 | - *https://XX-XXXXXXXX-gh.circle-artifacts.com/0/home/ubuntu/blog/generated-site* みたいなURLで見られるようになります(具体的なページはビルド結果ごとに異なるので、適宜ご案内します)。
21 |
22 | 結果、これまでHaskell-jp Blogに投稿する際に問題となっていた、下記の点が解消されました。
23 |
24 | - 投稿する人が自分で`make`などを実行しなければ、markdownで書いた記事がどのようなHTMLに変換されるかわからなかった。
25 | - 権限を持った人が`make deploy`するまで、記事をmasterブランチにマージしても公開されなかった。
26 |
27 | 以上を踏まえた、Haskell-jp Blogの投稿手順については、[README](https://github.com/haskell-jp/blog#readme)をご覧ください。
28 | 基本的に投稿する人は、**Markdownで記事を書いて、Pull requestを送るだけ**です!
29 |
30 | それでは、これからもHaskell-jp Blogをよろしくお願いします! hask(\_ \_)eller
31 | なお、現在Haskell-jp Blogでは、[Haskell Advent Calendar 2017](https://qiita.com/advent-calendar/2017/haskell)(と[その2](https://qiita.com/advent-calendar/2017/haskell2)、[その3](https://qiita.com/advent-calendar/2017/haskell3))の記事を特に精力的に募集しています。
32 | ぜひこの機会にHaskell-jp Blogに記事を投稿してみませんか?
33 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2017/windows-gotchas.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: WindowsでHaskellを扱う時によく遭遇するエラーと対処法
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: 雑なまとめ
6 | author: Yuji Yamamoto
7 | postedBy: Yuji Yamamoto(@igrep)
8 | date: December 25, 2017
9 | tags:
10 | ...
11 | ---
12 |
13 | この記事は、[Haskell (その4) Advent Calendar 2017](https://qiita.com/advent-calendar/2017/haskell4)14日目の記事です。
14 | 枠が空いていたので埋めるために登録しました。
15 | 長くかかった割には実験自体は失敗気味な、[昨日のこちらの記事](https://haskell.jp/blog/posts/2017/typesafe-precure2.html)よりは有用な情報じゃないかと思います。
16 | ほかの言語でもありそうな話ですしね。
17 |
18 | すごく簡潔にまとめるとこの間の下記のツイートに収まるのですが、もう少し丁寧に補足するために書きます。
19 |
20 |
21 |
22 |
23 | # Invalid characterと言われたらchcp 65001しよう
24 |
25 | 恐らく一番高確率で遭遇する & 知らないと回避できないのがこれ。
26 | あ、ほらまたhakyllでビルドしたら起きた!
27 |
28 | ```
29 | > stack exec -- site rebuild
30 | ...
31 | [ERROR] preprocessed-site\posts/2017/01-first.md: hGetContents: invalid argument (invalid byte sequence)
32 | ```
33 |
34 | GHCがファイルを読み書きする時に使う[`Handle`](https://www.stackage.org/haddock/lts-10.0/base-4.10.1.0/System-IO.html#t:Handle)というオブジェクトには、文字コードの情報が含まれています。
35 |
36 | これはRubyの[`IO`](https://docs.ruby-lang.org/ja/latest/class/IO.html)やPerlのファイルハンドラーにあるような仕組みと大体似ていて、`Handle`といったデータの「入り口」を表すオブジェクトに文字コードを紐付けることで、外から入ってくる文字列の文字コードを確実に内部の統一された文字コードに変換してくれます。
37 | Haskellの`Char`型の場合はUTF-32(この場合その言い方でよかったっけ?)のはずです。
38 |
39 | この`Handle`に紐付ける文字コード、当然のごとくデフォルトではOSのロケール設定に従って設定されるようになってまして、日本語版のWindowsではそう、Windows-31J(またの名をCP932)ですね。
40 | でも今はもうすぐ2018年。あなたが「メモ帳」でプログラムを書く人でもない限り、新しく作るファイルの大半はUTF-8でしょう。
41 | UTF-8とWindows-31Jは全然違う体系の文字コードなので、UTF-8なファイルをWindows-31Jのファイルとして読もうとしてもうまくいかないわけです。
42 | 冒頭にあげた`invalid byte sequence`というエラーはまさにそうした場合に起こるエラーです。
43 | ファイルの読み書きだけでなく標準入出力でもしばしば発生するので覚えておいてください。
44 |
45 | ## 対策
46 |
47 | ### ユーザーとして出くわした場合
48 |
49 | 多くの場合、このエラーは以下のコマンドをあらかじめ実行しておけば回避できます。
50 |
51 | ```
52 | > chcp 65001
53 | > stack exec -- site rebuild
54 | ... 動くはず!
55 | ```
56 |
57 | これは、現在開いているコマンドプロンプトで一時的に文字コードを切り替えるコマンドです。
58 | `65001`という数字がUTF-8を指しているようです。
59 | もとに戻したい場合は`chcp 932`と実行しましょう。
60 |
61 | ```
62 | > chcp 932
63 | ```
64 |
65 | どうやら「CP932」の「932」はここで出てくる「932」と同じものを指しているようですね!
66 |
67 | どういう仕様なのか分かりませんが、このコマンド、MSYS2のbashでも使用できます。
68 | ただし`chcp`コマンドは`C:\Windows\System32\`という、MSYS2ユーザーにとってはあまり`PATH`に入れたくない場所に入っています。
69 | このディレクトリーには、`find.exe`など、Unixな方が好んで使うコマンドと同じ名前の非互換なコマンドがゴロゴロ転がっているのです!
70 |
71 | なので私はMSYS2を使う時は`C:\Windows\System32\`は`PATH`から抜いています。
72 | 私と同じような方は下記のようにフルパスで実行しましょう。
73 |
74 | ```
75 | /c/Windows/System32/chcp.com 932
76 | ```
77 |
78 | ### それでもダメな場合、あるいはライブラリーなどの開発者として出くわした場合
79 |
80 | 残念ながら、`chcp 65001`してもこのエラーが消えないことはあります[^eta-20127]。
81 | 私の推測なんですが、どうも`chcp 65001`は`chcp 65001`したコマンドプロンプト(とかbash)の孫プロセス(つまり、あなたが入力したコマンドの子プロセス)には届かないことがあるようです。
82 |
83 | [^eta-20127]: 敢えて脚注に書きますが、[Eta](http://eta-lang.org/)のコンパイラーをビルドしている時(のはず)、`chcp 65001`でもダメで`chcp 20127`ならうまくいったことがあります。
84 | `chcp 20127`はUS-ASCIIに切り替えるためのコマンドですが、やっぱりEtaの開発者の手元(?)ではそうなっているからなのでしょうか...?
85 |
86 | そんなときは、実際にエラーが起きているコマンドの開発元にバグ報告するか、自分で直してみましょう。
87 | バグ報告する場合は、「`chcp 932`してから実行してみて」とお願いすると、バグ報告を受けた開発者も再現しやすくて助かるかも知れません(残念ながら私はやったことがありません)。
88 | 自分で直す場合、いろいろ方法はありますが、対象の`Handle`オブジェクトの文字コードを変えることで対処するのが、一番直接的で確実でしょう。
89 |
90 | この問題は`Handle`に設定された文字コードと実際にやりとりされる文字列の文字コードに食い違いが発生しているため起こるものなのですから、適切な文字コードに変えてしまえばいいのです。
91 | 状況にもよりますがエラーが起きた`Handle`が普通のUTF-8なファイルを読み書きするものである場合、下記のようにすれば、問題は回避できるはずです。
92 |
93 | ```haskell
94 | import System.IO (hSetEncoding)
95 | import GHC.IO.Encoding (utf8)
96 |
97 | hSetEncoding handle utf8
98 | ```
99 |
100 | それから、[実際に私がhaddockのバグを直した時](https://github.com/haskell/haddock/pull/566)を例に標準出力(または標準エラー出力)でこのエラーが発生した時の対応も紹介しておきます。
101 | コードだけ貼り付けると、下記のようにすれば少なくともエラーが起こらないようにすることはできます([このコミット](https://github.com/haskell/haddock/pull/566/commits/855118ee45e323fd9b2ee32103c7ba3eb1fbe4f2)とほぼ同じ内容です)。
102 |
103 | ```haskell
104 | {-# LANGUAGE CPP #-}
105 |
106 | import System.IO (hSetEncoding, stdout)
107 |
108 | #if defined(mingw32_HOST_OS)
109 | import GHC.IO.Encoding.CodePage (mkLocaleEncoding)
110 | import GHC.IO.Encoding.Failure (CodingFailureMode(TransliterateCodingFailure))
111 | #endif
112 |
113 | ...
114 |
115 | #if defined(mingw32_HOST_OS)
116 | liftIO $ hSetEncoding stdout $ mkLocaleEncoding TransliterateCodingFailure
117 | #endif
118 | ```
119 |
120 | Windowsでしか使用できないモジュールを`import`している関係上、CPPのマクロが混ざって読みにくいですが、重要な部分だけ切り出すと、
121 |
122 | ```
123 | hSetEncoding stdout $ mkLocaleEncoding TransliterateCodingFailure
124 | ```
125 |
126 | とすればよいのです。
127 |
128 | 一つ一つ解説しましょう。
129 | まず`hSetEncoding`は先ほども触れたとおり指定した`Handle`の文字コードを変更する関数です。
130 | そして`stdout`は名前の通り標準出力を表す`Handle`です。
131 | 最後の`mkLocaleEncoding TransliterateCodingFailure`ですが、これはWindowsで設定された文字コード(`chcp`された文字コードと同じ)を作って、「もし(Unicodeから、あるいはUnicodeに)変換できない文字があった場合、エラーにせず、それっぽい文字に変換する」という設定で返す、という意味です。
132 |
133 | 結果、`chcp 932`な状態でGHCのエラーメッセージにも使われる
134 |
135 | ```
136 | ↓この文字
137 | • No instance for (Transformation Nagisa CardCommune_Mepple)
138 | ↑
139 | ```
140 |
141 | が、
142 |
143 | ```
144 | ? No instance for (Transformation Nagisa CardCommune_Mepple)
145 | ```
146 |
147 | のように、クエスチョンマークに変換されるようになります。そう、日本語のWindowsでGHCをお使いの方は一度は目にした「?」ではないでしょうか😅
148 | つまりGHCはデフォルトで`hSetEncoding stderr $ mkLocaleEncoding TransliterateCodingFailure`しているものと推測されます。
149 | いずれにせよ、エラーでプログラムが異常終了しないだけマシですね。
150 |
151 | 更に補足すると、GHCの文字コードについてより詳しい情報は、[GHC.IO.Encodingのドキュメント](https://hackage.haskell.org/package/base-4.10.1.0/docs/GHC-IO-Encoding.html)をご覧ください。
152 |
153 | # Permission Deniedと言われたらビルドし直そう
154 |
155 | 雑なまとめと言いつつ最初の一つ目が長くなってしまいましたが、ここからは簡単に言います。
156 | Windowsで`stack build`なり`ghc`なり`elm-make`なりとにかくいろいろ動かしていると、「Permission Denied」と言ったエラー(あるいはこれと似たようなメッセージのエラー)に出遭います。
157 | 正直に言って私は原因はサッパリ分かってないのですが、このエラーは大抵の場合何度も同じコマンドを実行すれば再現しませんでした。
158 | 一度や二度ではめげず、繰り返すのがポイントです 😅
159 | 問題が起きているディレクトリーをウィルス対策ソフトのスキャン対象から外してみるとか、Dropboxの同期を一時的に止めてみる、といったこともやってみるといいかもしれません。
160 |
161 | あ、あと、「Directory not empty」みたいなのもあったかな。これは同類のはずです。
162 |
163 | # Cのライブラリーは... まぁ、頑張れ。
164 |
165 | Pure Haskellなライブラリーであれば大体OKなんですが、残念ながらCのライブラリー(`lib***`みたいな名前でよくOSのパッケージマネージャーに登録されているやつですね)に依存したライブラリーは、Windowsでインストールするのは結構トラブることが多いです。
166 | まぁ、これはHaskellに限った話ではないでしょう。
167 |
168 | 対応方法は私が知る限り完全にケースバイケースなので、ここでは知っている対応例をいくつか挙げておきましょう。
169 |
170 | - HDBC-sqlite3:
171 | - [Windows版stackでもHDBC-sqlite3をビルドする - Qiita](https://qiita.com/igrep/items/d947ab871eb5b20b57e4)
172 | - [MSYS2でHDBC-sqlite3をコンパイル - 北海道苫小牧市出身の初老PGが書くブログ](http://hiratara.hatenadiary.jp/entry/2017/01/29/110100)
173 | - [Haskell - Haskellにてstackでiconvパッケージを利用する方法【Windows環境】(102462)|teratail](https://teratail.com/questions/102462)
174 |
175 | 以上です!
176 | それでは2018年もHaskell on Windows 10でHappy Hacking!! WSLなんて知らないぜ!🏁🏁🏁
177 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2018/derive-json-no-prefix.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: deriveJsonNoPrefixをリリースしました
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: レコードラベルにprefixを着けざるを得ない人達に送るライブラリーです
6 | author: Yuji Yamamoto
7 | postedBy: Yuji Yamamoto(@igrep)
8 | date: July 18, 2018
9 | tags:
10 | ...
11 | ---
12 |
13 | 前回の更新からちょっと時間が空いてしまいました 💦
14 | 小ネタです。掲題の通り[deriveJsonNoPrefix](http://hackage.haskell.org/package/deriveJsonNoPrefix)というパッケージをリリースしました。
15 | 地味に有用だと思うので、[README](https://gitlab.com/igrep/deriveJsonNoPrefix/blob/master/README.md)をやや意訳気味に翻訳して記事にします。
16 | 十分に単純なので、仕様が変わることもまさかないでしょうし。
17 |
18 | 以下、[こちらのコミットの時点のREADME](https://gitlab.com/igrep/deriveJsonNoPrefix/blob/6114e0fc55cf5b57a771871e53971a51592f618b/README.md)の翻訳です。
19 |
20 | # deriveJsonNoPrefix
21 |
22 | プレフィックスに優しい`ToJSON`と`FromJSON`のインスタンスを定義するTemplate Haskellのマクロを提供します。
23 |
24 | ## 例
25 |
26 | こんな感じのJSONを作りたいとしましょう:
27 |
28 | ```json
29 | {
30 | "id": "ID STRING",
31 | "max": 0.789,
32 | "min": 0.123
33 | }
34 | ```
35 |
36 | きっと[ToJSON](http://hackage.haskell.org/package/aeson/docs/Data-Aeson.html#t:ToJSON)(おそらくそれに加えて[FromJSON](http://hackage.haskell.org/package/aeson/docs/Data-Aeson.html#t:FromJSON)も)のインスタンスを自動的に定義するための、次のようなレコード型を定義したくなるでしょう。
37 |
38 | ```hs
39 | {-# LANGUAGE TemplateHaskell #-}
40 |
41 | import Data.Aeson.TH
42 |
43 | data SomeRecord = SomeRecord
44 | { id :: String
45 | , max :: Double
46 | , min :: Double
47 | } deriving (Eq, Show)
48 |
49 | $(deriveToJSON defaultOptions ''SomeRecord)
50 | ```
51 |
52 | しかし、こんなレコード型は定義すべきではありません。
53 | `id`も`max`も`min`も、`Prelude`に定義済みなのですから!
54 |
55 | この問題を回避するために、レコードラベルに型の名前をプレフィックスとして加える、ということをわれわれはよくやります。
56 |
57 | ```hs
58 | data SomeRecord = SomeRecord
59 | { someRecordId :: String
60 | , someRecordMax :: Double
61 | , someRecordMin :: Double
62 | } deriving (Eq, Show)
63 | ```
64 |
65 | そして、`deriveToJSON`にデフォルトと異なるオプションを渡して実行します。
66 |
67 | ```hs
68 | deriveToJSON Json.defaultOptions { fieldLabelModifier = firstLower . drop (length "SomeRecord") } ''SomeRecord
69 |
70 | firstLower :: String -> String
71 | firstLower (x:xs) = toLower x : xs
72 | firstLower _ = error "firstLower: Assertion failed: empty string"
73 | ```
74 |
75 | `fieldLabelModifier`オプションは文字通り、対象のレコードをJSONに変換するとき、あるいはJSONから対象のレコードの値に変換する時、レコードのラベルを変換する関数を設定するために使います。
76 | 👆の場合、プレフィックスである`SomeRecord`の文字数分レコードラベルから`drop`して、先頭の文字(`someRecordId`で言えば`Id`の`I`に相当します)を小文字に変換しているのがわかるでしょうか?
77 |
78 | そう、これが`deriveToJsonNoTypeNamePrefix`がやっていることとほぼ同等のことです。
79 | `deriveToJsonNoTypeNamePrefix`は、実質次のように定義されています。
80 |
81 | ```hs
82 | deriveToJsonNoTypeNamePrefix :: Name -> Q [Dec]
83 | deriveToJsonNoTypeNamePrefix deriver name =
84 | deriveToJSON Json.defaultOptions { fieldLabelModifier = dropPrefix name } name
85 |
86 | dropPrefix :: Name -> String -> String
87 | dropPrefix name = firstLower . drop (length $ nameBase name)
88 |
89 | firstLower :: String -> String
90 | firstLower (x:xs) = toLower x : xs
91 | firstLower _ = error "firstLower: Assertion failed: empty string"
92 | ```
93 |
94 | 結果、これからは`fieldLabelModifier`をもう自分で定義する必要がありません!🙌
95 |
96 | ```hs
97 | import Data.Aeson.DeriveNoPrefix
98 |
99 | $(deriveJsonNoTypeNamePrefix ''SomeRecord)
100 | ```
101 |
102 | 👆 の`deriveJsonNoTypeNamePrefix` は [deriveJSON](https://hackage.haskell.org/package/aeson/docs/Data-Aeson-TH.html#v:deriveJSON)と同様に、`ToJSON`と`FromJSON`のインスタンス、両方を生成します。
103 | もちろん、`FromJSON`のインスタンスを生成するときのオプションとしても、プレフィックスを削除するための`fieldLabelModifier`を渡してくれます!
104 |
105 | ## 同じ問題を解決するほかのライブラリー
106 |
107 | - [extensible](https://hackage.haskell.org/package/extensible).
108 | - など、`ToJSON`・`FromJSON`のインスタンスが定義されたextensible recordを提供するライブラリー
109 |
110 | なので、そうしたextensible recordを提供するライブラリーが学習コストや依存関係などの事情で「重たい」と感じたときにこのパッケージを使ってください。
111 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2018/haskell-day-2018.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskell Day 2018 開催レポート
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | author: Kazuki Okamoto
6 | postedBy: Kazuki Okamoto (@kakkun61)
7 | date: November 20, 2018
8 | tags: イベント
9 | ---
10 |
11 | こんにちはkakkun61こと岡本和樹です。
12 |
13 | 去る11月10日にHaskell Day 2018が開催されましたので、そのイベントレポートをお送りします。
14 |
15 | # Haskell Day 2018とは
16 |
17 |
18 |
19 | [https://haskell-jp.connpass.com/event/92617/](https://haskell-jp.connpass.com/event/92617/)
20 |
21 | Haskell Dayは2012年2016年と不定期に開催しており今回で3度目となります。
22 |
23 | 2018年の今回は「Haskellちょっと興味あるからちょっとできるまで」というテーマで開催されました。
24 |
25 |
26 |
27 | # セッション
28 |
29 | ## 「作りながら学ぶHaskell入門」を使ったハンズオン
30 |
31 | 開発中の対話的チュートリアル[「作りながら学ぶHaskell入門」](https://github.com/haskell-jp/makeMistakesToLearnHaskell)を使って、参加者の皆さんにもくもくと入門していただきました。「作りながら学ぶHaskell入門」では、簡単な課題を解くことで、Haskellの初歩的な使い方を学びつつ、学んだ知識をその場でテストできます。
32 |
33 | [https://github.com/haskell-jp/makeMistakesToLearnHaskell](https://github.com/haskell-jp/makeMistakesToLearnHaskell)
34 |
35 |
36 |
37 | ----
38 |
39 | ## Haskellを導入した話とHRRの紹介
40 |
41 | [
](https://htmlpreview.github.io/?https://github.com/khibino/haskell-day-2018/blob/master/presentation.html)
42 |
43 |
44 |
45 | ----
46 |
47 | ## Servantで実現する高速かつ安全なAPI開発
48 |
49 |
50 |
51 |
52 |
53 | ----
54 |
55 | ## 並列並行言語Haskell
56 |
57 |
58 |
59 |
60 |
61 | ----
62 |
63 | ## Dhall: Haskellの新たなキラーアプリ
64 |
65 |
66 |
67 | ----
68 |
69 | ## Semigroupとは?Monoid?環?
70 |
71 | [
](https://aiya000.github.io/Maid/haskell-day-2018-algebra/#/)
72 |
73 |
74 |
75 | ----
76 |
77 | ## HaskellでCLI
78 |
79 |
80 |
81 |
82 |
83 | ----
84 |
85 | ## gloss: 動かして遊んで学ぶHaskell
86 |
87 | [
](https://qiita.com/lotz/items/bdb04c771efc8919b79c)
88 |
89 |
90 |
91 | ----
92 |
93 | ## Lisztあるいは永続データ構造を真に永続させる方法
94 |
95 | [
](https://shared-assets.adobe.com/link/353213c2-281a-4a53-6cff-a52bff1314c1)
96 |
97 |
98 |
99 | ## 懇親会
100 |
101 | スポンサーとしてIIJに飲食物の提供をしていただきました。
102 |
103 |
104 |
105 | # アンケート
106 |
107 | 約110名の方が出席し約40名の方が回答してくださいました。
108 |
109 | 参加できなくなった約40名の方は事前のキャンセルをよろしくお願いします。
110 |
111 | ## Haskellを始めてどれくらい経ちますか?
112 |
113 |
114 |
115 | ここ1年以内に始めた方が全体の21.4%、1年以上5年未満前に始めた方がちょうど半分程度となりました。1年以上5年未満前に始めた方の57%の方は今でもHaskellを使い続けているようです。
116 |
117 | 5年以上前に始めた方は全体の1/4となりました。
118 |
119 | ## 読んだことのある日本語のHaskell本は?
120 |
121 |
122 |
123 | 項目は下記となります。
124 |
125 | - すごい Haskell たのしく学ぼう!
126 | - プログラミング Haskell
127 | - Haskell による並列・並行プログラミング
128 | - 関数プログラミング実践入門 ── 完結で正しいコードを書くために
129 | - 関数プログラミング入門 ── Haskell で学ぶ原理と技法
130 | - Real World Haskell
131 | - 関数プログラミング ── 珠玉のアルゴリズムデザイン
132 | - 簡約!λカ娘
133 | - Haskell ── 教養としての関数型プログラミング
134 | - その他(自由記述)
135 |
136 | この項目にはアンケートの途中で追加したものもあるので、結果があまり厳密でないことに注意してください。
137 |
138 | その他の選択肢で自由記述では次の票がありました。
139 |
140 | - Haskell入門 10票
141 | - ふつうのHaskell 1票
142 | - Haskellによる関数プログラミングの思考法 1票
143 |
144 | # 終わりに
145 |
146 | 参加者の発表者、スタッフのみなさんのおかげで無事開催することができました。ありがとうございました。
147 |
148 | 今後ともHaskell-jpをよろしくお願いします。
149 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2018/main-tester.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CLIアプリのE2Eテストを行うためのライブラリー main-testerをリリースしました
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: たまにはHaskellらしからぬ(?)テストも書いてみよう!
6 | author: Yuji Yamamoto
7 | postedBy: Yuji Yamamoto(@igrep)
8 | date: April 9, 2018
9 | tags:
10 | ...
11 | ---
12 |
13 | こんにちは。みなさん、テストは書いてますか?
14 | 「[Haskellライブラリ所感2016](http://syocy.hatenablog.com/entry/haskell-library-2016#%E3%83%86%E3%82%B9%E3%83%88)」という記事でも紹介されているとおり、Haskellにも様々なテスト用ライブラリーがあります。
15 | 今回は、「Haskellライブラリ所感2016」でも紹介されている[silently](https://hackage.haskell.org/package/silently)というパッケージにインスパイアされた、新しいテスト用ライブラリーを作りました。
16 | タイトルにも書きましたが[main-tester](https://hackage.haskell.org/package/main-tester)といいます。
17 |
18 | # main-testerができること
19 |
20 | main-testerは名前の通り、`main`関数のテストをサポートするライブラリーです。
21 | Haskell製のプログラムを起動すると最初に実行される、あの`main`関数です。
22 |
23 | `main`関数は`IO ()`という型であるとおり、原則として必ず入出力を伴うので、自動テストがしにくい関数です。
24 | 一般的なベストプラクティスとしては、できるだけ`IO`でない、純粋な関数を中心にテストを書いていくのが普通でしょう。
25 | それでも敢えて`main`関数の自動テストを書くのには、以下のメリットがあります。
26 |
27 | 1. `main`関数をテストすると言うことは、作っているコマンドの、ユーザーの要求に最も近いレベルのテスト、E2Eテスト(end-to-end テスト)をすることができる。
28 | 1. `main`関数(や、その他の`IO`を伴う関数)に対するテストは、データベースやファイルシステムなど、外部のソフトウェアとの「組み合わせ」で起こるバグを検出できる。
29 | - 経験上、特に単純なアプリケーションでは、そうした外部のソフトウェアに対する「誤解」が原因となったバグが比較的多いように感じています。
30 | 1. 私の個人的な都合ですが、趣味では小さなアプリケーションを書くことが多いので、そうしたE2Eテストの方が効果的だったりする。
31 |
32 | このように、`main`関数をはじめとする、`IO`な関数に対して敢えて自動テストを書くことには、様々なメリットがあります。
33 | `main-tester`はそうした`IO`な関数をテストする際に伴う、2つの問題を解決しました。
34 |
35 | 1. 標準出力・標準エラー出力に出力した文字列がテストしにくい
36 | - ➡️ `captureProcessResult`という関数で、標準出力・標準エラー出力に出力した文字列をそれぞれ`ByteString`として取得することができます。
37 | 1. 標準入力から文字列を読み出そうとすると、テストの実行が停止してしまう。
38 | - ➡️ `withStdin`という関数で、標準入力に与えたい文字列を`ByteString`として与えることができます。
39 |
40 | ここに書いたことは、ビルドした実行ファイルを子プロセスとして呼び出すことによってもできます。
41 | 入出力の順番など、標準出力や標準エラー出力のより細かい挙動をテストするにはその方がいいでしょう[^thread]。
42 | しかし、テストのために`PATH`を分離させる必要があったり、そのために[`stack exec`を使ったらめっちゃ遅い](https://github.com/commercialhaskell/stack/issues/2885)という問題があったり、そもそも子プロセス呼び出しはそれだけでオーバーヘッドがあったりと、様々な問題があります。
43 | 物事をよりシンプルにするには、`main`関数を直接呼び出した方がよいでしょう。
44 | main-testerは、CLIアプリケーションのE2Eテストにおける、そうした子プロセスの呼び出しの問題と、より大きな関数をテストしたいというニーズに応えるためのライブラリーなのです。
45 |
46 | [^thread]: `main`関数を子スレッドとして`forkIO`することで同じことが恐らくできますが、テスト結果の報告に使うべき、標準出力・標準エラー出力を食い合うことになってしまうので、非常にやりづらいと思います。
47 |
48 | # ほかのライブラリーとの違い
49 |
50 | 「silentlyというパッケージにインスパイアされた」と冒頭で申しましたとおり、前節で紹介した機能は、実はすでにほかのライブラリーに似たものがあります。
51 | silentlyに加え、[imperative-edslというパッケージに含まれる、`System.IO.Fake`というモジュール](https://hackage.haskell.org/package/imperative-edsl-0.7.1/docs/System-IO-Fake.html)です(ほかにもあったらすみません!🙇🙇🙇)。
52 | これらとmain-testerとの違いは何でしょう?
53 |
54 | 第一に、先ほども触れましたが、main-testerの`captureProcessResult`関数や`withStdin`関数は、標準出力・標準エラー出力・標準入力でやりとりする文字列をstrictな`ByteString`でやりとりします。
55 | silentlyや`System.IO.Fake`は、`String`なのです。
56 | `ByteString`は文字通り任意のバイト列を扱うことができるので、「Unicodeの文字のリスト」である`String`よりも、多様なデータを扱うことができます。
57 |
58 | これは、特に複数の種類の文字コードを扱うとき、非常に重要な機能となります。
59 | [以前の記事で取り上げた、`Invalid character`というエラー](https://haskell.jp/blog/posts/2017/windows-gotchas.html)を再現させる場合も、ないと大変やりづらいでしょう。
60 |
61 | 第二に、main-testerの`captureProcessResult`関数は、`main`関数の終了コードも[`ExitCode`型](https://hackage.haskell.org/package/base-4.11.0.0/docs/System-Exit.html#t:ExitCode)の値として取得できます。
62 | `main`関数の中で`exitFailure`等の関数を呼び出すと、`ExitCode`が例外として投げられます。
63 | 既存のライブラリーでこれを行うと、`ExitCode`が例外として処理されるため、テストしたい`main`関数の実行が終了してしまいます。
64 | 結果、`main`関数が標準出力・標準エラー出力に書き込んだ文字列を取得することができないのです。
65 | 「○○というエラーメッセージを出力して異常終了する」といったことをテストしたい場合、これでは使いづらいでしょう。
66 | **「`main`関数のE2Eテストを行うためのライブラリーである」**という観点から、必須の機能であると判断し、実装しました。
67 | ちなみに、`ExitCode`以外の例外についてはそのまま投げられます。仕様を単純にするために、これはユーザーのテストコードの中で処理することとしています。
68 |
69 | # 使い方・バグ報告
70 |
71 | 機能は非常にシンプルなので、使い方については[ドキュメント](https://hackage.haskell.org/package/main-tester-0.1.0.0/docs/Test-Main.html)のサンプルコードを読めば大体わかるかなぁと思いますが、簡単にサンプルを載せておきましょう。
72 |
73 | 例えばこんなソース👇のプログラムがあった場合、
74 |
75 | ExampleMain.hs:
76 |
77 | ```haskell
78 | module ExampleMain where
79 |
80 | import Data.List
81 | import System.Exit
82 |
83 | main :: IO ()
84 | main = do
85 | putStr "What's your name?: "
86 | name <- getLine
87 | if "Yuji" `isInfixOf` name
88 | then putStrLn "Nice name!"
89 | else die $ name ++ "? Sorry I don't know such a guy!"
90 | ```
91 |
92 | main-testerを使えば、次のようにHspecでテストできます。
93 |
94 | ExampleSpec.hs:
95 |
96 | ```haskell
97 | {-# LANGUAGE OverloadedStrings #-}
98 |
99 | import System.Exit
100 | import Test.Main
101 | import Test.Hspec
102 | import qualified ExampleMain
103 | import qualified Data.ByteString as B
104 |
105 | main = hspec $
106 | describe "your-cool-command" $ do
107 | context "Given 'Yuji' to stdin" $
108 | it "prints a string including 'Nice name' without an error" $ do
109 | result <- withStdin "Yuji"$ captureProcessResult ExampleMain.main
110 | prExitCode result `shouldBe` ExitSuccess
111 | prStderr result `shouldSatisfy` B.null
112 | prStdout result `shouldSatisfy` ("Nice name" `B.isInfixOf`)
113 |
114 | context "Given other name to stdin" $
115 | it "prints an error message" $ do
116 | result <- withStdin "other name" $ captureProcessResult ExampleMain.main
117 | prExitCode result `shouldBe` ExitFailure 1
118 | prStderr result `shouldSatisfy` (not . B.null)
119 | ```
120 |
121 | それぞれのファイルを同じディレクトリーに置いた上で、次のように実行すれば試せるはずです (cabalユーザーの皆さんは適当に読み替えてください...)。
122 |
123 | ```bash
124 | > stack build hspec main-tester
125 | > stack exec runghc -- --ghc-arg=-i. ExampleSpec.hs
126 |
127 | your-cool-command
128 | Given 'Yuji' to stdin
129 | prints a string including 'Nice name' without an error
130 | Given other name to stdin
131 | prints an error message
132 |
133 | Finished in 0.0130 seconds
134 | 2 examples, 0 failures
135 | ```
136 |
137 | バグを見つけたら[こちらのGitLabのIssue](https://gitlab.com/igrep/main-tester/issues)に報告してください(最近の個人的な判官贔屓により、敢えてGitLabにしております 😏)。
138 | それではこの春はmain-testerでHappy Haskell Testing!! 💚💚💚
139 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2018/renew-haskell-antenna.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskell Antenna をリニューアルしました
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | author: MATSUBARA Nobutada
6 | postedBy: MATSUBARA Nobutada(@matsubara0507)
7 | date: March 21, 2018
8 | tags: Haskell-jp
9 | ---
10 |
11 | [Haskell Antenna](https://haskell.jp/antenna/)は[lotz84](https://github.com/lotz84)氏が作ったHaskellの日本語情報を収集するウェブサイトです。
12 | 下記の記事を読むと、動機付けなどが分かると思います。
13 |
14 | - [Haskell Antenna を公開しました - Haskell-jp](https://haskell.jp/blog/posts/2017/03-haskell-antenna.html)
15 |
16 | 残念なことにHaskell Antennaは動作が重く、なかなか満足に閲覧することが出来ませんでした。
17 | そこで、Haskell Antennaをリニューアルしました!
18 |
19 | 正確には、[Planet Haskell](https://planet.haskell.org/)の日本語版として作成した[もの](https://github.com/matsubara0507/planet-haskell-jp-demo)を、新しいHaskell Antennaとして置き換えました。
20 | 新Antennaは旧Antennaと比べると見た目も機能も更新頻度も残念なことになってしまいましたが、各サイトのフィードから記事の一覧を取得し静的サイトとして生成しているだけなので動作は軽快です。
21 |
22 | 旧Antenna同様に新Antennaでも配信する情報源(今のところAtomかRSS2.0形式のフィード)をいつでも募集しています。
23 | もし追加すべき情報源にアイデアがあれば[GitHubレポジトリのREADME](https://github.com/haskell-jp/antenna#サイトの追加方法)にかかれている方法を参考にPull Requestを送っていただくことが可能です。
24 | また、PRを送るのは面倒だという方はHaskell-jpのSlackの#antennaチャンネルを通じて提案を行ってもらうことも大歓迎です。
25 | (Planet Haskellがそうであるように)Haskell中心でなくても良いので、Haskellの情報を発信しているブログを持っている方は是非、追加提案をしていただけると助かります。
26 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2018/tech-book-fest-5.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 技術書典 5 での Haskell 関連サークルのまとめ
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | author: Kazuki Okamoto
6 | postedBy: Kazuki Okamoto (@kakkun61)
7 | date: October 5, 2018
8 | tags: 書籍
9 | ---
10 |
11 | こんにちはkakkun61こと岡本和樹です。
12 |
13 | 来たる10月8日(月・祝)に池袋にて技術系同人誌即売会「技術書典5」が開催されます。
14 |
15 | Haskellを題材にした同人誌もいくつかあるようですのでまとめてみました。
16 |
17 | # 技術書典とは?
18 |
19 |
20 |
21 | (バナー画像は技術書典5サイトよりの引用です。)
22 |
23 | 技術書典とは技術系同人誌即売会としておそらく日本最大のもので、今回で6回目の開催となります。(ニコニコ超会議内での超技術書典があったのでナンバリングがずれています。)
24 |
25 | - [サイト](https://techbookfest.org/event/tbf05)
26 | - [ブログ](https://blog.techbookfest.org/)
27 | - [Twitter](https://twitter.com/techbookfest)
28 |
29 | これまでは秋葉原での開催でしたが、今回はなんと場所を3倍の広さに拡張して池袋で開催されます。
30 |
31 | それにともないサークル数もどどんと470超となり、1サークル45秒で回っても全サークルは見て回れないことになります。
32 |
33 | 事前準備の重要性が高まった今回、Haskeller向けにHaskellサークルをまとめてみました。
34 |
35 | # か36 — 鴨川書房
36 |
37 | [カタログ](https://techbookfest.org/event/tbf05/circle/32370012)
38 |
39 | ## Data A la carte vol. 1
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | # か38 — だめぽラボ
48 |
49 | [カタログ](https://techbookfest.org/event/tbf05/circle/37190001)
50 |
51 | ## 代数的数を作る 多項式の根と因数分解のアルゴリズム
52 |
53 | - 同人誌
54 | - 268ページ
55 | - ¥2500
56 |
57 | [ブログの告知記事](https://blog.miz-ar.info/2018/09/techbookfest5/)
58 |
59 | > 代数的数(整数係数多項式の根として表される数)を実装するためのアルゴリズムを解説します。代数的数を使うと、ルートを含むような数に関して、浮動小数点数の誤差に煩わされることなく正確な演算が行えます。Haskellによるサンプルコードを掲載しています。
60 | >
61 | > この本は、Web連載していた「週刊 代数的実数を作る」 https://miz-ar.info/math/algebraic-real/ の書籍化です。本文の加筆修正の他、「付録A ユークリッドの互除法と拡張された互除法」「付録B 部分分数分解」を追加しています。
62 | >
63 | > [カタログ](https://techbookfest.org/event/tbf05/circle/37190001)より
64 |
65 |
66 |
67 |
68 | # か61 — 趣味はデバッグ……
69 |
70 | 私のサークルです。新刊落としました……
71 |
72 | ## 手続きHaskell
73 |
74 | [カタログ](https://techbookfest.org/event/tbf05/circle/45000003)
75 |
76 | - 同人誌
77 | - 28ページ
78 | - ¥500
79 | - [http://doujin.kakkun61.com/procedural-haskell](http://doujin.kakkun61.com/procedural-haskell)
80 |
81 | > Haskellでの手続きプログラミングの側面について解説します。
82 | >
83 | > 対象読者
84 | > - Haskell入門書程度が読める
85 | > - 特に読めるが書こうとすると悩む人に読んでほしいです
86 | > - 手続きプログラミングのプログラマー
87 | > - 厳密に本書を読むためにはHaskellを読めた方がよいですが、手続きプログラミングですのでプログラマーなら雰囲気で読めると思います
88 | >
89 | > 書かれてあること
90 | > - 書き換え可能な変数
91 | > - 手続きプログラミング的な制御構造
92 | > - 配列
93 | > - サンプルプログラム
94 | > - 手続き的な実装とHaskell的な実装の対比
95 | >
96 | > 電子版(PDF)はこちらで販売中です。
97 | > https://kakkun61.booth.pm/items/829369
98 | >
99 | > [カタログ](https://techbookfest.org/event/tbf05/circle/45000003)より
100 |
101 | ## Haskellで作るWebアプリケーション 遠回りして学ぶYesod入門
102 |
103 | - 商業誌
104 | - 76ページ
105 | - ¥1500
106 | - [https://nextpublishing.jp/book/9979.html](https://nextpublishing.jp/book/9979.html)
107 |
108 | > 【HaskellのウェブアプリケーションフレームワークYesodの入門書!】
109 | >
110 | > 本書は、Haskellの入門書レベルの知識をもつ読者を対象とした、ウェブアプリケーションフレームワークYesodの入門書です。比較的学習コストの高いYesodですが、本書を通じてYesodの基本的な知識とHaskellでのウェブアプリケーション開発に挑んで見ましょう!
111 | > 〈本書の対象読者〉
112 | > Haskellの入門書は既に読みこなしているプログラマ
113 | > Haskellでウェブアプリを作ってみたいプログラマ
114 | >
115 | > [出版社ページ](https://nextpublishing.jp/book/9979.html)より
116 |
117 | ちなみにこんな本を作るつもりでした。欲しい方いらっしゃったら次で書けとお伝えください。はげみになります。
118 |
119 |
120 |
121 |
122 | # か74 — 大宇宙銀河No.1-Haskeller-にこにー
123 |
124 | [カタログ](https://techbookfest.org/event/tbf05/circle/43260001)
125 |
126 | ## 矢澤にこ先輩といっしょに代数!
127 |
128 | - 同人誌
129 | - 84ページ
130 | - ¥1000
131 |
132 | [ブログの告知記事](http://aiya000.github.io/posts/2018-09-12-techbookfest5.html)
133 |
134 | > ゆるふわにこまき数学!
135 | >
136 | > 以下のような人に向けて、頒布します。
137 | >
138 | > - 数学・代数の雰囲気をゆるく知りたい
139 | > - 軽いHaskellを知りたい
140 | > - なんでもいいから技術系にこまきが読みたい
141 | >
142 | > [カタログ](https://techbookfest.org/event/tbf05/circle/43260001)より
143 |
144 |
145 |
146 |
147 | # それでは当日に
148 |
149 | 当日は安全に配慮しつつ楽しんでいきましょう!!
150 |
151 | 1000円札と500円玉の準備はしっかりとね。
152 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2018/topic-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskell-jp Blogで書いてほしいネタを募集します!
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | subHeading:
6 | author: Haskell-jp
7 | tags: Haskell-jp
8 | postedBy: Haskell-jp
9 | date: February 18, 2018
10 | ...
11 | ---
12 |
13 | Haskell-jp Blogでは、設立当初よりHaskellに関する記事を幅広く募集してきました。
14 | このたびはそれに加え、このHaskell-jp Blogで「書いて欲しい!」「読んでみたい!」Haskellに関する話題も募集することにしました!
15 | 例えば、下記のような話題が考えられるでしょう。
16 |
17 | - ○○パッケージの解説記事が欲しい
18 | - 数学用語とHaskell用語の対応関係が知りたい
19 | - Real World Haskellを今読むならの注意点
20 | - そのほか、Haskellに関する話題であれば何でも!
21 |
22 | **ただし、提案していただいたネタに関する知見の持ち主が居ないかもしれませんし、誰かの負担になるものなので必ず記事になるとは限りません。**
23 | また、場合によっては既に記事があるため、既存の記事を薦められるかもしれません。
24 |
25 | ## ネタを提案してくれる場合
26 |
27 | [このBlogのリポジトリのIssue](https://github.com/haskell-jp/blog/issues/new?template=topic-request.md&labels=Topic+Request)からお願いします。
28 | 既に提案されていたら、そのIssueに対して 👍 するといいと思います。
29 |
30 | ## 書いてもいいよって場合
31 |
32 | `TopicRequest` というラベルを作ったので、[Issueをそのラベルで検索](https://github.com/haskell-jp/blog/issues?q=is:issue+is:Aopen+label:"Topic+Request")してください。
33 | 書いてもいいという提案があった場合は、Issueに「書いてもいいよ」という旨をコメントしていただけるとバッティングが無くて助かります。
34 |
35 |
36 | それでは、今後はHaskellに関するあなたの記事だけでなく、あなたがHaskellについて読みたい記事も募集していきますので、どしどし応募してください! 🙏
37 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2018/unordered-containers-hash-dos.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: hashdos脆弱性とunordered-containers
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: HashMap・HashSetの利用時は注意!
6 | author: Yuji Yamamoto
7 | postedBy: Yuji Yamamoto(@igrep)
8 | date: January 21, 2018
9 | tags: Security
10 | ...
11 | ---
12 |
13 | あらゆるソフトウェアに脆弱性は存在し得ます。
14 | Haskellは高度な型システムを駆使することで、脆弱性を根本的に回避したプログラムを作ることを可能にします(脆弱性を防ぐためだけのものではないですが、興味のある人は[Safe Haskell](http://www.kotha.net/ghcguide_ja/7.6.2/safe-haskell.html)についても調べてみるといいでしょう)。
15 | しかし、だからといって、型を設計する段階で脆弱性を回避できるよう気をつけなければいけないことには変わりませんし、GHCが生成した実行ファイル、使用するライブラリーに絶対に脆弱性がないとは言えません。
16 | 現状、Haskellはほかの著名なプログラミング言語ほど使用されていないためか、あまり脆弱性が報告されることはありません(libcなど、ほかの言語の処理系も依存しているようなライブラリーの脆弱性は別として)。
17 | 今回は、そんな中でも[unordered-containersというパッケージ](https://hackage.haskell.org/package/unordered-containers)について、[ドキュメントにも書かれている](https://github.com/tibbe/unordered-containers/blob/60ced060304840ed0bf368249ed6eb4e43d4cefc/docs/developer-guide.md#security)ため**おそらく直ることがないであろう脆弱性**と、その回避方法について紹介します。
18 | hashdos脆弱性自体は結構有名ですし、ドキュメントに書いてあることなので、ご存知の方には何を今更感があるかと思いますが、検索した限りこの問題について日本語で説明した記事は見当たらなかったので、ここで紹介します。
19 |
20 | # そもそもunordered-containersって?
21 |
22 | 脆弱性の前にunordered-containersパッケージについて簡単に紹介しましょう。
23 | [unordered-containersパッケージ](https://hackage.haskell.org/package/unordered-containers)は、GHCに標準で付いている[containersパッケージ](https://hackage.haskell.org/package/containers)よりも高速な連想配列([`HashMap`型](https://hackage.haskell.org/package/unordered-containers-0.2.8.0/docs/Data-HashMap-Lazy.html))や集合([`HashSet`型](https://hackage.haskell.org/package/unordered-containers-0.2.8.0/docs/Data-HashSet.html))を提供してくれます。
24 | [StackageのLTS Haskell 10.3ではなんと970ものパッケージに依存されている](https://www.stackage.org/lts-10.3/package/unordered-containers-0.2.8.0)、超大人気汎用パッケージです。
25 |
26 | ## どうやって高速化しているの?
27 |
28 | `HashMap`という名前が示しているとおり、キーとなる値のハッシュ値を計算・利用することで高速化しています。
29 | しかし、Java言語などほかの言語によくある`HashMap`とは大きく異なり、内部ではハッシュテーブルを使用していません。
30 | [本物のプログラマはHaskellを使う - 第35回 キーを使って値を参照するMap型:ITpro](http://itpro.nikkeibp.co.jp/article/COLUMN/20091104/340002/?rt=nocnt)でも説明しているとおり、ハッシュテーブルはミュータブルな配列を内部で使用していることから、イミュータブルなデータ構造を使用して行う関数型プログラミングとは、相性が悪いのです(`ST`モナドや`IO`モナドを利用した[hashtablesパッケージ](https://hackage.haskell.org/package/hashtables)などを使えば、限られた範囲内でハッシュテーブルを使うこともできます)。
31 |
32 | ハッシュテーブルを使用しない代わりに、unordered-containersでは内部で[Hash array mapped trie](https://en.wikipedia.org/wiki/Hash_array_mapped_trie)という特殊な木を使っています。
33 | どのような構造かは、[HAMT ~ イミュータブルで高速なハッシュマップ ~ | κeenのHappy Hacκing Blog](http://keens.github.io/slide/HAMT/)に詳しく書かれています。
34 | こちらのスライドはScalaでの実装の話ですが、基本的にはunordered-containersパッケージの`HashMap`も同じはずです。
35 |
36 | 大雑把に言うと、Hash array mapped trieを使った`HashMap`では、ハッシュテーブルと同様に、キーとなる値を**ハッシュ関数で一旦固定長の整数に変換する**ことで、キーが存在しているかどうかの確認を高速化しています。そのため、containersパッケージよりも高速な処理ができるのです。
37 | containersパッケージの`Map`ではキーの存在を確認する際、キー全体を既存のキーと比較する必要があるため、特に長い文字列をキーとする場合は、処理が遅くなりがちだったのです。
38 |
39 | # hashdos脆弱性とは?
40 |
41 | hashdos脆弱性は[2011年頃RubyやPHP、Perlなど多くのプログラミング言語が影響を受けるとされた](https://blog.tokumaru.org/2011/12/webdoshashdos.html)、著名な脆弱性です。
42 | ここでも簡単に仕組みを説明しましょう。
43 |
44 | 前節で説明したとおり、Hash array mapped trieもハッシュテーブルも、必ずキーを一旦固定長の整数に変換します。
45 | 文字列など、ハッシュ関数を適用されるキーとなる値は、当然固定長の整数よりも幅広い値を取り得るので、違う文字列同士でも、同じハッシュ値をとることがあります。
46 | この、違う値であるはずのキーが同じハッシュ値をとってしまった状態を「ハッシュ値の衝突」と呼びます。
47 | ハッシュ値の衝突が発生した場合、ハッシュテーブルやHash array mapped trieといったハッシュ値を利用した連想配列は、(単純な)配列やリストなど、やむを得ず逐次探索が必要なデータ構造を内部で使用しなければならなくなります。
48 |
49 | hashdos脆弱性はこの性質を利用したDoS攻撃です。
50 | 攻撃者は、あらかじめ対象のプログラムで使っているハッシュ関数が、「必ず同じハッシュ値」を返すキー(大抵文字列でしょう)を大量に用意して、それを対象のプログラムに入力として与えることで、簡単にDoS攻撃を仕掛けることができるのです。
51 | [先ほど触れた徳丸先生の記事](https://blog.tokumaru.org/2011/12/webdoshashdos.html)では、PHPのアプリケーションに対してわずか500KBのform-dataを送るだけでCPU時間を1分も消費させることができたそうですから、その威力はすさまじいものと言えるでしょう。
52 |
53 | # なぜ直さないのか?
54 |
55 | [unordered-containersのDeveloper Guide](https://github.com/tibbe/unordered-containers/blob/60ced060304840ed0bf368249ed6eb4e43d4cefc/docs/developer-guide.md#security)には、次のように書かれています。
56 |
57 | > There's an uncomfortable trade-off with regards to security threats posed by e.g. denial of service attacks. Always using more secure hash function, like SipHash, would provide security by default. However, those functions would make the performance of the data structures no better than that of ordered containers, which defeats the purpose of this package.
58 |
59 | 要するに、「セキュリティー上問題はあるけど、SipHashのような安全なハッシュ関数を使ったらcontainersパッケージよりも速度が出なかった。それではこのパッケージの意味がない」ということです。
60 | containersパッケージよりも高速な連想配列を作るためにunordered-containersパッケージを作ったのだから、それより遅くなっては存在価値がなくなってしまうのです。
61 | 従って、ユーザーが任意にキーを入力できるようなプログラムでは、unordered-containersではなく、containersを使え、ということです。
62 | このことはunordered-containersが使用している[hashableのドキュメント](https://hackage.haskell.org/package/hashable-1.2.6.1/docs/Data-Hashable.html#g:1)にも書かれています。ある意味ノーガード戦法ですね。
63 |
64 | # 回避方法
65 |
66 | 前節で触れたとおりですが、**ユーザーが任意にキーを入力できるようなプログラム**では、unordered-containersパッケージの`HashMap`や`HashSet`ではなく、containersパッケージの`Map`や`Set`を使いましょう。
67 | containersパッケージにある`Map`や`Set`はハッシュ関数を一切使っていないので、ハッシュ値の衝突も起こらず、内部で逐次探索が必要なデータ構造を使ってもいません。
68 | なのでhashdos攻撃に遭うことはないのです。
69 |
70 | ただし、実際のところ、[StackageのLTS Haskell 10.3で970ものパッケージに依存されている](https://www.stackage.org/lts-10.3/package/unordered-containers-0.2.8.0)unordered-containersです。
71 | ~~その中にはJSONのパーサーであるaesonも含まれているので、もしかしたら現状回避するのは非常に困難なのかもしれません。😱~~
72 | ~~次回は、この問題について試しに攻撃用のコードを書いて速度の低下をチェックして報告する話を書くかもしれません...。😰~~
73 |
74 | **2022/10/23 追記**: aesonパッケージがHashDoS脆弱性を孕んでいるという問題は、[2021年9月に発表され](https://cs-syd.eu/posts/2021-09-11-json-vulnerability)、同脆弱性はaesonパッケージのv2.0.1.0で修正されました。現在は、コンパイル時のフラグを編集しない限り、内部でcontainersパッケージの`Map`を使うようになりました。ただし、[フラグのデフォルト値は将来変更するかも知れない、と開発者が明言している](https://github.com/haskell/aeson/issues/864#issuecomment-939363297)ので、心配な方はcabal.projectやstack.yamlでフラグの値を指定しましょう([参考](https://frasertweedale.github.io/blog-fp/posts/2021-10-12-aeson-hash-flooding-protection.html#compiling-a-safe-version-of-aeson))。この記事を書いた時点で当然私もこの問題には気づいていたのですが、再現ケースの作成に失敗したこともあり、報告に至らなかったことを反省します。本件を発表した記事と同じ、[fnv-collider](https://github.com/Storyyeller/fnv-collider)を使ったはずなのになぁ😞。
75 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2018/windows-long-path.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: WindowsでHaskellを扱う時によく遭遇するNo such file or directoryについて
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: 短いパスにしよう
6 | author: Yuji Yamamoto
7 | postedBy: Yuji Yamamoto(@igrep)
8 | date: March 13, 2018
9 | tags:
10 | ...
11 | ---
12 |
13 | 去年、[WindowsでHaskellを扱う時によく遭遇するエラーと対処法](/posts/2017/windows-gotchas.html)という記事で、WindowsユーザーがHaskellで開発したとき、あるいはHaskell製のプログラムを使用した際によく遭遇するエラーやその回避方法を紹介しました。
14 | 今回は、そこに追記したい内容として、最近私がよく出遭うようになったエラーを紹介します。
15 |
16 | # `openFile: does not exist (No such file or directory)`といわれたら短いパスに移そう
17 |
18 | `does not exist (No such file or directory)`というエラーは、本当に読んで字のごとく、開こうとしたファイルが存在しないためのエラーであることとがもちろん多いのですが、エラーメッセージに反して違う原因である場合もあります。
19 |
20 | 例えば、最近私はとあるプロジェクトを数文字長い名前にリネームしたのですが、たったそれだけで、`stack test`した際必ず問題のエラーが発生するようになってしまいました。
21 |
22 | ```
23 | $ stack test
24 | a-little-longer-name-project-0.1.0.0: build (lib + exe + test)
25 | Preprocessing library for a-little-longer-name-project-0.1.0.0..
26 | Building library for a-little-longer-name-project-0.1.0.0..
27 | Preprocessing executable 'mmlh' for a-little-longer-name-project-0.1.0.0..
28 | Building executable 'mmlh' for a-little-longer-name-project-0.1.0.0..
29 | Preprocessing test suite 'a-little-longer-name-project-test' for a-little-longer-name-project-0.1.0.0..
30 | Building test suite 'a-little-longer-name-project-test' for a-little-longer-name-project-0.1.0.0..
31 | [1 of 5] Compiling Paths_aLittleLongerNameProject ( .stack-work\dist\5c8418a7\build\a-little-longer-name-project-test\autogen\Paths_aLittleLongerNameProject.hs, .stack-work\dist\5c8418a7\build\a-little-longer-name-project-test\a-little-longer-name-project-test-tmp\Paths_aLittleLongerNameProject.o )
32 | .stack-work\dist\5c8418a7\build\a-little-longer-name-project-test\a-little-longer-name-project-test-tmp\.stack-work\dist\5c8418a7\build\a-little-longer-name-project-test\autogen\Paths_aLittleLongerNameProject.dump-hi: openFile: does not exist (No such file or directory)
33 | ```
34 |
35 | どういうことかと悩んでいたところ、[こんなIssue](https://github.com/commercialhaskell/stack/issues/3649)を見つけました。
36 | [Snoymanの指摘](https://github.com/commercialhaskell/stack/issues/3649#issuecomment-351612621)のとおり、こちらの問題はWindowsで使えるパスの長さが原因のエラーのようです。
37 | どういうことかというと、[MSDNのこちらのページ](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%20\(v=vs.85\)#maxpath)でも触れているとおり、Windowsの(C言語レベルでの)各種ファイル操作用APIでは、一度に扱えるパスの長さが260文字までと決められていて、その制限にかかったためのエラーだというのです!
38 | `does not exist (No such file or directory)`なんてエラーメッセージで表されるのでわかりづらい!(おそらくWindowsのエラーコードの出し方に問題があるんじゃないかと思います)
39 |
40 | DOS時代から残るこの制限、完全に時代錯誤なものでしかないのですが、Windowsでパッケージマネージャーなどが自動的に作ったパスを扱っていると、しばしば出くわすことがあります。
41 | stackにおいても、[こちらのIssue](https://github.com/commercialhaskell/stack/issues/3285)で同じ問題が議論されていたり、[ver. 1.6.5のChangeLog](https://github.com/commercialhaskell/stack/releases/tag/v1.6.5)でも言及されていたりと、至る所で格闘している跡があります。
42 |
43 | ## 回避方法
44 |
45 | そんな`does not exist (No such file or directory)`ですが、残念ながら私が知る限り、プロジェクトなどのパスを(`C:\`などのよりルートに近い場所に置いて)より短くする以外の回避方法はありません。
46 | [haskell-ide-engineのインストール方法のページ](https://github.com/haskell/haskell-ide-engine#installation-on-windows)曰く、(新しめの)Windows 10であれば、グループポリシーを編集して、「Win32の長いパスを有効にする」を「有効」にすれば回避できるとのことですが、残念ながら手元で試した限りうまくいきませんでした。何かやり方がまずかったのかもしれませんが。
47 | いずれにしても、`stack build`コマンドなどを実行したときに問題のエラーに遭遇した場合、ビルドしたいもののパスをなんとかして短くする以上の方法はありません。
48 | `C:\`直下をホームディレクトリのように使う人が今でもたくさんいるわけです。
49 |
50 | 一方、あなたが問題のエラーが発生するプログラムを**修正する**ことができる立場にある場合、次の方法で回避できるかもしれません。
51 |
52 | ### 長いパスをより短くするために、カレントディレクトリーを変更して、相対パスを短くする。
53 |
54 | 本件はあくまでも、Windowsの各種ファイル操作用APIの1回の呼び出しで渡せる長さの制限ですので、制限を超えてしまうような場合はパスを分割すればよいのです。
55 | [filepathパッケージの`splitFileName`関数](https://hackage.haskell.org/package/filepath-1.4.2/docs/System-FilePath-Posix.html#v:splitFileName)や[`splitPath`関数](https://hackage.haskell.org/package/filepath-1.4.2/docs/System-FilePath-Posix.html#v:splitPath)を駆使してパスを分割した上で、対象のファイルの親ディレクトリーまで[directoryパッケージの`setCurrentDirectory`関数](https://hackage.haskell.org/package/directory-1.3.2.1/docs/System-Directory.html#v:setCurrentDirectory)で移動すれば、制限に引っかからないはずです(時間の都合でこちらについては試すコードを用意しておりません。あしからず)。
56 |
57 | 残念ながらカレントディレクトリーはプロセス全体で共有される情報ですので、マルチスレッドなプログラムでは頭の痛い問題が出てきてしまいますが、一番確実に回避できる方法のはずです。
58 | マルチスレッドである場合を考慮したくない場合は、次に紹介する方法を検討するとよいでしょう。
59 |
60 | ### Win32 APIのユニコード版の関数に、`\\?\`というプレフィックスを着けた絶対パスを渡す。
61 |
62 | ここまでに出てきた、「Windowsの各種ファイル操作用API」は、すべて「Win32 API」と呼ばれるWindows固有のAPI群の一部です。
63 | この「Win32 API」に含まれる関数の多くは、「ユニコード版」とそうでないものに分かれます(詳細は[Conventions for Function Prototypes (Windows)](https://msdn.microsoft.com/ja-jp/library/windows/desktop/dd317766\(v=vs.85\).aspx)をご覧ください)。
64 |
65 | このうち、「ユニコード版」のAPIには、この制限を緩和する専用の機能が含まれています。
66 | 先ほども触れた[MSDNのページ](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%20\(v=vs.85\)#maxpath)曰く、なんと`\\?\`という変な文字列を絶対パスの頭に着けると、最大約32,767文字のパスまで受け付けるようになるというのです!
67 | なんともアドホックな感じのする解決方法ですが、Microsoftが言うんだから間違いありません。
68 | いずれにしても32,767文字という微妙な最大文字数ができてしまいますが、UTF-16での32,767文字なので、そう簡単に超えることはないでしょう。
69 | いちいち絶対パスに変えて変なプレフィックスを加えないといけないという面倒くささはありますが、いちいち分割して相対パスに変換するよりは簡単なはずですので、検討する価値があります。
70 |
71 | この、`\\?\`機能を試す場合、下記のコードを適当なファイルに貼り付けて保存し、`stack runghc file.hs`などと実行してみてください (Thanks, @matsubara0507!)。
72 | `catch`関数を使って例外を捕捉している箇所では、実際にパスが長すぎるためにエラーが発生し、`catch`されているはずです。
73 |
74 | ```haskell
75 | import Control.Exception (catch, IOException)
76 | import Data.List (replicate)
77 | import System.Directory
78 |
79 | main :: IO ()
80 | main = do
81 | crDir <- getCurrentDirectory
82 | let
83 | path1 = mconcat $ replicate 20 "abcdefgh/" -- ok
84 | path2 = mconcat $ replicate 30 "abcdefgh/" -- error
85 | path3 = crDir ++ "/" ++ path2 -- error
86 | path4 = "\\\\?\\" ++ path3 -- ok
87 |
88 | putStrLn $ "path1: " ++ show path1
89 | createDirectoryIfMissing True path1
90 |
91 | putStrLn $ "path2: " ++ show path2
92 | createDirectoryIfMissing True path2 `catch` (\e -> putStrLn $ " " ++ show (e :: IOException))
93 |
94 | putStrLn $ "path3: " ++ show path3
95 | createDirectoryIfMissing True path3 `catch` (\e -> putStrLn $ " " ++ show (e :: IOException))
96 |
97 | putStrLn $ "path4: " ++ show path4
98 | createDirectoryIfMissing True path4
99 | ```
100 |
101 | # おわりに
102 |
103 | さて、またしてもWindows固有の面倒な問題を紹介することとなってしまいましたが、俗世の喜び(主にゲーム)と簡単にインストールできるGUIに慣らされてしまった私は、今後もWindowsを使い続けるつもりです。
104 | いろいろ困難は尽きませんがこれからもWindowsでHappy Haskell Lifeを!🏁🏁🏁
105 |
106 | # 参考URL
107 |
108 | ※本文中で言及していないもののみ
109 |
110 | - [プログラマ的にWindows 10 Anniversary Updateのうれしいところ - kkamegawa's weblog](http://kkamegawa.hatenablog.jp/entry/2016/07/27/220014)
111 | - [Windows 10 "Enable NTFS long paths policy" option missing - Super User](https://superuser.com/questions/1119883/windows-10-enable-ntfs-long-paths-policy-option-missing)
112 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2019/fallible.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: fallibleというパッケージをリリースしました
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | author: Nobutada MATSUBARA
6 | postedBy: Nobutada MATSUBARA(@matsubara0507)
7 | date: July 18, 2019
8 | tags:
9 | ...
10 | ---
11 |
12 | タイトルの通り、fallibleというパッケージを紹介します。
13 |
14 | - [matsubara0507/fallible: interface for fallible data type like Maybe and Either. - GitHub](https://github.com/matsubara0507/fallible)
15 |
16 | ちなみに、fallibleはHaskell-jp Slackで:
17 |
18 |
19 |
20 | と質問したところ、該当するようなパッケージは無さそうだったので作ったという経緯があります。
21 | その際に助言をくれた [fumieval](https://github.com/fumieval)氏のコードをほとんど引用した形になったので、Haskell-jp Blogに紹介記事を載せることにしました(僕は普段、自分のブログに自作したパッケージを書いています)。
22 |
23 | ## fallibleパッケージ
24 |
25 | Haskellでアプリケーションを記述してると次のようなコードを書くことがありますよね?
26 |
27 | ```Haskell
28 | import qualified Data.List as L
29 |
30 | run :: String -> Token -> Bool -> IO ()
31 | run targetName token verbose = do
32 | users <- getUsers token
33 | case users of
34 | Left err -> logDebug' err
35 | Right us -> do
36 | case userId <$> L.find isTarget us of
37 | Nothing -> logDebug' emsg
38 | Just tid -> do
39 | channels <- getChannels token
40 | case channels of
41 | Left err -> logDebug' err
42 | Right chs -> do
43 | let chs' = filter (elem tid . channelMembers) chs
44 | mapM_ (logDebug' . channelName) chs'
45 | where
46 | logDebug' = logDebug verbose
47 | emsg = "user not found: " ++ targetName
48 | isTarget user = userName user == targetName
49 |
50 | logDebug :: Bool -> String -> IO ()
51 | logDebug verbose msg = if verbose then putStrLn msg else pure ()
52 | ```
53 |
54 | Slackのようなチャットツールをイメージしてください。
55 | 該当の名前(`targetName`)を持つユーザーを与えると、そのユーザーが参加しているチャンネルの一覧を表示するというような振る舞いです。
56 | こう段々になってしまうのは気持ち悪いですよね。
57 | fallibleの目的はこの段々を次のように平坦にすることです(`where` などは割愛):
58 |
59 | ```Haskell
60 | import Data.Fallible (evalContT, exit, lift, (!?=), (???))
61 |
62 | run :: String -> Token -> Bool -> IO ()
63 | run targetName token verbose = evalContT $ do
64 | users <- lift (getUsers token) !?= exit . logDebug'
65 | targetId <- userId <$> L.find isTarget users ??? exit (logDebug' emsg)
66 | channels <- lift (getChannels token) !?= exit . logDebug'
67 | lift $ mapM_ (logDebug' . channelName) $
68 | filter (elem targetId . channelMembers) channels
69 | ```
70 |
71 | ### やってること
72 |
73 | というか、もともとのアイデアは下記のブログです:
74 |
75 | - [ContT を使ってコードを綺麗にしよう! - BIGMOON Haskeller's BLOG](https://haskell.e-bigmoon.com/posts/2018/06-26-cont-param.html)
76 |
77 | これを一般化(`Maybe a` 固有ではなく `Either e a` でも使う)できないかなぁというのがもともとの発想です。
78 |
79 | ### 基本演算子
80 |
81 | 次の4つの演算子を利用します:
82 |
83 | ```Haskell
84 | (!?=) :: Monad m => m (Either e a) -> (e -> m a) -> m a
85 | (!??) :: Monad m => m (Maybe a) -> m a -> m a
86 | (??=) :: Applicative f => Either e a -> (e -> f a) -> f a
87 | (???) :: Applicative f => Maybe a -> f a -> f a
88 | ```
89 |
90 | ただし、内部実装的には `Maybe a` や `Either e a` は `Fallible` 型クラスで一般化されています:
91 |
92 | ```Haskell
93 | class Applicative f => Fallible f where
94 | type Failure f :: *
95 | tryFallible :: f a -> Either (Failure f) a
96 |
97 | instance Fallible Maybe where
98 | type Failure Maybe = ()
99 | tryFallible = maybe (Left ()) Right
100 |
101 | instance Fallible (Either e) where
102 | type Failure (Either e) = e
103 | tryFallible = id
104 |
105 | (!?=) :: (Monad m, Fallible t) => m (t a) -> (Failure t -> m a) -> m a
106 | (???) :: (Applicative f, Fallible t) => t a -> f a -> f a
107 | ```
108 |
109 | これらを継続モナドと組み合わせることでIOと失敗系モナド(`Maybe a` や `Either e a`)を、モナドトランスフォーマーなしにDo記法で書くことができます!
110 |
111 | ```Haskell
112 | -- 継続モナドに関する関数
113 | evalConstT :: Monad m => ContT r m r -> m r
114 |
115 | exit :: m r -> ContT r m a
116 | exit = ContT . const
117 | ```
118 |
119 | ## サンプルコード
120 |
121 | 疑似的なIOで良いなら[fallibleリポジトリのexampleディレクトリ](https://github.com/matsubara0507/fallible/tree/master/example)にあります(上述の例はそれです)。
122 |
123 | 実際の利用例であれば、最近自作した[matsubara0507/mixlogue](https://github.com/matsubara0507/mixlogue)というHaskellアプリケーションで多用しています([ココ](https://github.com/matsubara0507/mixlogue/blob/8afd16ab4048ff62976b8e38347078fdaa7417dd/src/Mixlogue/Cmd.hs#L81-L93)とか[ココ](https://github.com/matsubara0507/mixlogue/blob/8afd16ab4048ff62976b8e38347078fdaa7417dd/src/Mixlogue/Message.hs#L15-L25)とか)。
124 | ちなみに、mixlogueは特定のSlackの分報チャンネル(`times_hoge`)の発言を収集するというだけのツールです。
125 |
126 | ## 使い方
127 |
128 | READMEを参照してください。
129 |
130 | 現状Hackageにはあげてないので、stackやCabalでGitHubリポジトリから参照する方法を利用してください。
131 |
132 | ## おしまい
133 |
134 | fumieval氏のコードをほとんど引用するだけになったので自分でリリースするか迷ったんですけど、リリースしてくれというのも丸投げがひどいので自分でリリースしました。
135 | まぁこういう結果が生まれるのもOSSコミュニティの醍醐味ということで。
136 | fumieval氏、いつもアドバイスをくれてありがとう!
137 |
138 | (もちろん他のHaskell-jpの皆さんも!)
139 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2019/haskell-in-vrchat.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: VRのためにHaskellを使った話
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | author: Haruka Nakajima
6 | postedBy: Haruka Nakajima(@haru2036)
7 | date: December 03, 2019
8 | tags: Spock, VRChat
9 | ...
10 | ---
11 |
12 | # はじめに
13 | はじめまして。趣味でHaskellしているはる(haru2036)と申します。まったり進行で開発しているのでGHCのバージョンアップの速さについていけてない感があります……
14 | さて、今回はあんまり深い話はありません。どちらかと言うとこんなニッチなところにHaskell使ったよというネタで書きます。
15 |
16 | # VR空間でLTがしたい
17 | 突然ですが、私は[VRChat](https://vrchat.com/)(以下VRC)というソーシャルVRサービス(Second LifeのVR版みたいなものです)にハマっています。
18 | 友人との雑談の中でVRCの中でLT会ができればプログラミングなどの話題で盛り上がれる人が集まってワイワイ楽しくできるのではないかと話して、その場のノリでとりあえず実装してみることにしました。
19 |
20 | 
21 |
22 | 今回作りたかったのはスライドを表示するためのスクリーンと、ページ送りに使うボタンを実装したワールドです。
23 |
24 | 
25 |
26 | VRCではアバターやワールドを自由に作ることができるのですが、VRCが提供するコンポーネント以外のスクリプトは利用できません。Haskellユーザとしては得意なことを活用しづらい土壌です。
27 | 幸いスライドを表示する手段はゲーム内でURLから画像を取得し表示するVRC_Panoramaというコンポーネントを利用することにより確保できましたが、VRC_Panoramaが取得できる画像はワールド作成時に決め打ちで指定されたURLのリストに含まれるもののみです。
28 | そのため、スライド画像へのURLのリストを直接VRC_Panoramaに渡していると、イベントを開催する際よくある飛び入り参加やスライドの用意が遅れた参加者に対応できなくなってしまいます。
29 |
30 | その問題を解決するために、イベント開始時からのページ数とスライドの画像URLをマップするWebAPIを用意しました。
31 | 具体的には、`/slides/{pageCount} ` のような形のエンドポイントを持ったAPIを用意し、そこから実際の画像へリダイレクトをかけるという方法を取りました。
32 |
33 | 
34 |
35 | # Webフレームワーク
36 | 今回は自分で使うだけだしということでさらっとやってみたかったのでSpockを利用しました。もう少し誰でも使えるサービスにしたいと考えているのでServantに載せ替えてかっちり作り直そうかと思い移植しているところです。
37 |
38 | # はじめてのHaskellペアプロ
39 | じつはLT会をやろうと思いついた友人の[BOXP](https://twitter.com/b0xp2)はClojureユーザで、せっかくだからとAPIの開発を手伝ってくれました。
40 | あまりHaskellに馴染みはなかったものの、いわゆる関数型プログラミング的な概念はバッチリなのでスススっと書いてくれました。
41 | 書いてくれる上での障壁になったのは、型関連の要素(`data`や`type`や`newtype`がぱっと見わからなかった、型コンストラクタ、値コンストラクタの概念)に馴染みが薄かったことでした。
42 | Discordで画面共有しながら説明を行ったのですが、やはり同じ画面を見ながら説明するのはとてもやりやすいと感じました。
43 | 本人からのメッセージはこちら。
44 |
45 | > プログラミングHaskellを昔読んでかじったことがある程度で素人もいいところでしたが、当人のサポートもあり思いついた数日後には実装が終わっていました。
46 | > はるくんの話にもある通りDiscordで画面共有しながらペアプロし、Haskellでのテストコードの書き方も一から教えてもらいながら書きました。これは願ってもない体験だったので根気よく教えてくれたことに非常に感謝しています。
47 | >
48 | > また、個人的には実装以外でのブレストや実際の会場でのデバッグをVRChat上でできた事もとてもよかったなと思っています。
49 | > 単純に実装を確認するためには二人以上でVRChatに入る必要があるというのもありましたが、完全リモートでも身振り手振りありでブレストができたことや、アバターのおかげで環境に囚われないコミュニケーションができていたこともGoodでした。
50 |
51 | # デプロイ
52 | 今回は自分で使うだけな上に常時稼働している必要もなく、コストを最小限に抑えたかったのでHerokuにデプロイしました。
53 | Dockerfileを書き、スタティックリンク周りで悩みながらもイメージを生成してHerokuのレジストリにPushし、後はいつものHerokuという感じでうまくいきました。
54 |
55 | 余談ですが、最近参加したGotanda.hsというイベントで`cabal build --enable-executable-static`でいい感じにシングルバイナリが生成できるというお話を聞いたので、最近stackばっかり使ってたのを改めて適材適所で使い分けていきたいなーと思っています。
56 |
57 | # 実際に開催してみて
58 | ここはHaskellほぼ全く関係ないですが……
59 |
60 | 
61 | VRC-LTという名前で6回ほど開催しているのですが、場所の制約を受けずに勉強会ができ、その後の懇親会も会場の撤収時刻や終電を気にせず話したい人はとことん話し続ける事ができるというところが非常に良かったです。
62 | ホワイトボードはまだ未実装ですが、空間に書けるペンも配布されているのでその手のアイテムも取り入れれば懇親会での話も更にはずむのではないでしょうか。
63 |
64 | VRChatはPCのみでも利用することができます。
65 | VRC-LTはほぼ月イチペースで不定期開催ですので、もしよろしければ参加していただけると嬉しいです。
66 | 開催時のアーカイブ等も以下のWebサイトにて公開中です。合わせてご覧ください。
67 | [https://vrc-lt.github.io](https://vrc-lt.github.io)
68 |
69 | # リポジトリ
70 | そんなこんなで開発中のリポジトリはこちらになります。
71 | 拙いところもいっぱいですがIssueやPRなどで気になった点を教えていただければ幸いです!
72 | [https://github.com/vrc-lt/VRC-Slide-Server](https://github.com/vrc-lt/VRC-Slide-Server)
73 |
74 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2019/hiw-copilot.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: HIW 2019で発表された、Copilotという内部DSLについて
3 | subHeading: ~HIW 2019参加レポート その4~
4 | headingBackgroundImage: ../../img/background.png
5 | headingDivClass: post-heading
6 | author: Yuji Yamamoto
7 | postedBy: Yuji Yamamoto(@igrep)
8 | date: October 1, 2019
9 | tags: Haskell Implementors' Workshop
10 | ...
11 | ---
12 |
13 | [前回](/posts/2019/hiw-gibbon.html)から引き続き、[Haskell Implementors' Workshop 2019](https://icfp19.sigplan.org/home/hiw-2019#About)への参加レポートとして、私の印象に残った発表を紹介します。
14 | 今回は、[Copilot](https://copilot-language.github.io/)という、C言語のコードを生成するHaskell製内部DSLについての発表です。
15 |
16 | # Copilot 3.0: a Haskell runtime verification framework for UAVs
17 |
18 | 発表者: Frank Dedden *Royal Netherlands Aerospace Center*, Alwyn Goodloe *NASA Langley Research Center*, Ivan Perez *NIA / NASA Formal Methods*
19 |
20 | Haskell製の内部DSLからC言語のソースコードを生成する、[Copilot](https://copilot-language.github.io/)の紹介です。
21 | 似た謳い文句の内部DSLとして[ivory](http://hackage.haskell.org/package/ivory)がありますが、Copilotは、ハードウェアの実行時検証を行うC言語のコードを生成することに、より特化しています。
22 | 「センサーから信号を受け取って、一定の条件を満たした場合に何らかの処理を実行する」という処理をHaskellで宣言的に記述すると、メモリの消費量・実行時間において常に一定なC言語のコードを生成することが出来ます。
23 |
24 | メモリが限られていて、リアルタイムな処理が必要なハードウェアにとって「邪魔にならない監視」を実現するための必須条件なのでしょう。
25 | 現状HaskellはGCが必要であるといった制約もあり、リアルタイムな処理や厳格なメモリー管理が必要な機器での採用は難しいですが、Ivoryや今回発表されたCopilotはあくまでも「C言語のコードを生成するだけ」なので、生成するHaskellではメモリー管理をする必要がありません。
26 | にっくきスペースリークに悩まされる心配もないのです。
27 | こういったHaskell製内部DSLは、Haskellの持つ強い型付けによるメリットを享受しながら、変換した言語の実行時におけるパフォーマンスを出しやすい、といういいとこ取りなメリットがあるので、もっと広まってほしいユースケースですね。
28 |
29 | # Copilotを試してみる
30 |
31 | - ℹ️ 実際に使用したコードは[Haskell-jp BlogのGitHubのリポジトリー](https://github.com/haskell-jp/blog/tree/master/examples/2019/hiw-copilot)にあります。
32 | - ℹ️ 使用したcopilotパッケージのバージョンは、3.0.1です。
33 | - ℹ️ サンプルコードの解説については、notogawaさんのアドバイスも参考になりました([Haskell-jpのslack-logではこのあたり](https://haskell.jp/slack-log/html/C4M4TT8JJ/46.html#message-1554858057.072700)。執筆時点でCSSが当たってないため読みづらいですが一応)。ありがとうございます!
34 |
35 | せっかくなんでCopilotを試してみましょう。
36 | 公式サイトにあったサンプルコードそのまんまですが、生成されるCのコードを眺めてみます。
37 |
38 | 👇のコマンドでサンプルコードが入ったリポジトリーをgit cloneした後、
39 |
40 | ```bash
41 | git clone https://github.com/haskell-jp/blog
42 | cd blog/examples/2019/hiw-copilot
43 | ```
44 |
45 | 👇のコマンドでビルド・C言語によるコードの生成できるはずです。
46 |
47 | ```bash
48 | stack build copilot
49 | stack exec runghc heater.hs
50 | ```
51 |
52 | こちらが生成元のHaskellのコードです。
53 |
54 | ```haskell:heater.hs
55 | import Language.Copilot
56 | import Copilot.Compile.C99
57 |
58 | import Prelude hiding ((>), (<), div)
59 |
60 | temp :: Stream Word8
61 | temp = extern "temperature" Nothing
62 |
63 | ctemp :: Stream Float
64 | ctemp = (unsafeCast temp) * (150.0 / 255.0) - 50.0
65 |
66 | spec = do
67 | trigger "heaton" (ctemp < 18.0) [arg ctemp]
68 | trigger "heatoff" (ctemp > 21.0) [arg ctemp]
69 |
70 | main = reify spec >>= compile "heater"
71 | ```
72 |
73 | まず、`temp`と`ctemp`という識別子に定義した式が、センサーが発信する、連続的に変化する値を表しています。
74 | Copilotの言葉はこれを`Stream`と呼んでいます。
75 |
76 | `spec`という識別子で定義している式が、「どのセンサーから信号を受け取って、どんな条件を満たした場合にどの処理を実行するか」規定しているようです。
77 | 👆の場合、`ctemp`という`Stream`が`18.0`を下回ったら`heaton`というイベントを発火し、`21.0`を超えたら`heatoff`というイベントを発火する、と定めているわけですね。
78 | そして`main`関数で実行している`reify spec >>= compile "heater"`という箇所で、`.h`ファイルと`.c`ファイルを書き込んでいます。
79 |
80 | そして、生成されたヘッダーファイル`heater.h`がこう👇
81 |
82 | ```c:heater.h
83 | extern uint8_t temperature;
84 | void heatoff(float heatoff_arg0);
85 | void heaton(float heaton_arg0);
86 | void step(void);
87 | ```
88 |
89 | で、肝心のCのコード本体`heater.c`がこちらです。
90 |
91 | ```c:heater.c
92 | #include
93 | #include
94 | #include
95 |
96 | #include "heater.h"
97 |
98 | static uint8_t temperature_cpy;
99 |
100 | bool heatoff_guard(void) {
101 | return ((((float)(temperature_cpy)) * ((150.0) / (255.0))) - (50.0)) > (21.0);
102 | }
103 |
104 | float heatoff_arg0(void) {
105 | return (((float)(temperature_cpy)) * ((150.0) / (255.0))) - (50.0);
106 | }
107 |
108 | bool heaton_guard(void) {
109 | return ((((float)(temperature_cpy)) * ((150.0) / (255.0))) - (50.0)) < (18.0);
110 | }
111 |
112 | float heaton_arg0(void) {
113 | return (((float)(temperature_cpy)) * ((150.0) / (255.0))) - (50.0);
114 | }
115 |
116 | void step(void) {
117 | (temperature_cpy) = (temperature);
118 | if ((heatoff_guard)()) {
119 | (heatoff)(((heatoff_arg0)()));
120 | };
121 | if ((heaton_guard)()) {
122 | (heaton)(((heaton_arg0)()));
123 | };
124 | }
125 | ```
126 |
127 | 先ほど`Stream`として定義した値のうち、`temp`は、`temperature`というグローバル変数と、それを一時的に保存する`temperature_cpy`という二つの変数に翻訳されました。
128 | `spec`において`trigger`という関数で列挙した「どのセンサーから信号を受け取って、どんな条件を満たした場合にどの処理を実行するか」というルールは、`step`という関数に現れたようです。
129 | この関数を利用する側では、`heaton`関数と`heatoff`関数を別途定義した上で、`temperature`にセンサーから受け取った値を代入して`step`を呼ぶことによって、`temperature`の値が条件に一致したとき、`heaton`関数と`heatoff`関数を実行してハードウェアの制御ができるのでしょう。
130 | Haskell側で定義したもう一つの`Stream`、`ctemp`は、`heaton_guard`、`heaton_arg0`、`heatoff_guard`、`heatoff_arg0`、それぞれの関数に書かれた、`temperature_cpy`の値を変換する式に現れているようです。
131 |
132 | 正直なところこの程度であれば、直接Cで書いた方が余計なカッコもないし読みやすそうではあります。
133 | `temp`を`ctemp`に変換する式`(150.0 / 255.0) - 50.0`が変換後のソースコードでは冗長に適用されていることから、もっと最適化できそうですし。
134 | とはいえ、わざわざDSLを作ったからには、より複雑で、Haskellでなければ書いてられないようなケースが、Copilotの開発者の現場ではあるのでしょう(なんせNASAの方も関わっているぐらいですから!)。
135 | 詳しいユースケースや、ビルド時のフローといった運用方法を聞きたいところですね。
136 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2019/hiw-ghc-future.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: HIW 2019で発表された、GHC 8.10に導入されるであろう機能
3 | subHeading: ~HIW 2019参加レポート その2~
4 | headingBackgroundImage: ../../img/background.png
5 | headingDivClass: post-heading
6 | author: Yuji Yamamoto
7 | postedBy: Yuji Yamamoto(@igrep)
8 | date: September 17, 2019
9 | tags: GHC, Haskell Implementors' Workshop
10 | ...
11 | ---
12 |
13 | [前回](/posts/2019/hiw-ghc8.8.html)から引き続き、[Haskell Implementors' Workshop 2019](https://icfp19.sigplan.org/home/hiw-2019#About)への参加レポートとして、私の印象に残った発表をいくつか紹介します。
14 | 今回は、「GHC 8.10に導入されるであろう機能」です。
15 | いずれも該当するMerge Requestはmasterブランチにマージ済みなので、おそらくGHC 8.10で提供されるでしょう。
16 |
17 | ## HoleFitPlugins and the future of interactive development in GHC
18 |
19 | - 発表者: Matthías Páll Gissurarson *Chalmers University of Technology, Sweden*
20 | - 該当のMerge Request: [!153](https://gitlab.haskell.org/ghc/ghc/merge_requests/153)
21 | - 該当のGHC Proposal: なし
22 |
23 | [昨年のHaskell Symposiumでも発表](https://icfp18.sigplan.org/details/haskellsymp-2018-papers/10/Suggesting-Valid-Hole-Fits-for-Typed-Holes-Experience-Report-)されてGHC 8.6で導入された、「Valid Hole Fits」という機能のさらなる拡張について。
24 |
25 | まず、「Valid Hole Fits」という機能について軽く紹介します(詳しくは[こちらのスライド](https://wataru86.github.io/slides/vhs/)が参考になるかと思います)。
26 | 「Valid Hole Fits」はアンダースコア `_`で始まる識別子を書いたとき、GHCが推論した型にマッチする関数をエラーメッセージに付記することで、ユーザーがどんな式を書けばよいか、ヒントを与えてくれるものです。
27 |
28 | 例えば、
29 |
30 | ```haskell
31 | map (length . _someFunc) [True, False, True]
32 | ```
33 |
34 | 上記のように、アンダースコア `_`で始まる識別子を書いたとき、
35 |
36 | ```haskell
37 | :1:16: error:
38 | ...
39 | Valid hole fits include
40 | enumFrom :: forall a. Enum a => a -> [a]
41 | with enumFrom @Bool
42 | (imported from ‘Prelude’ (and originally defined in ‘GHC.Enum’))
43 | show :: forall a. Show a => a -> String
44 | with show @Bool
45 | (imported from ‘Prelude’ (and originally defined in ‘GHC.Show’))
46 | repeat :: forall a. a -> [a]
47 | with repeat @Bool
48 | (imported from ‘Prelude’ (and originally defined in ‘GHC.List’))
49 | return :: forall (m :: * -> *) a. Monad m => a -> m a
50 | with return @[] @Bool
51 | (imported from ‘Prelude’ (and originally defined in ‘GHC.Base’))
52 | pure :: forall (f :: * -> *) a. Applicative f => a -> f a
53 | with pure @[] @Bool
54 | (imported from ‘Prelude’ (and originally defined in ‘GHC.Base’))
55 | mempty :: forall a. Monoid a => a
56 | with mempty @(Bool -> [a0])
57 | (imported from ‘Prelude’ (and originally defined in ‘GHC.Base’))
58 | ```
59 |
60 | といった具合に、アンダースコアで始まる識別子`_someFunc`の型を`Bool -> [a0]`と推論した上で[^type-hole]、実際にその型に該当する関数を、当該のスコープにおいてアクセスできる関数の中から探して教えてくれる、それが「Valid Hole Fits」という機能です。
61 |
62 | [^type-hole]: 復習: この、「アンダースコアで始まる識別子`_someFunc`の型を`Bool -> [a0]`と推論した上で」エラーメッセージにおいて`Found hole: _someFunc :: Bool -> [a0]`と教えてくれるのが「Type Hole」という機能なのでした。
63 |
64 | 今回発表された「HoleFitPlugins」という機能は、名前のとおりこの「Valid Hole Fits」に対するプラグイン機構です。
65 | 「Valid Hole Fits」が表示する「型にマッチした関数」を探す処理を、Haskellのコードで書き換えられるようにしてくれます!
66 |
67 | 「そこまでする必要あるの?」という気もしてきますが、発表者曰く
68 |
69 | - Hoogleをはじめ、TensorFlowなどGHCの外部にあるものを利用して「型にマッチした関数」を探せるようにするために必要
70 | - GHCiとこの機構を組み合わせることで、もっとインタラクティブな開発を促進したい
71 |
72 | という意図があるそうです。
73 |
74 | 最新安定版のGHCでは利用できませんが、[ドキュメントがこちら](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/extending_ghc.html#hole-fit-plugins)にあるので、GHCのHEAD(masterブランチで開発中のバージョン)をコンパイルすれば使用できるようです。
75 |
76 | 加えて発表では、`_`で始まる識別子を書く際の構文を拡張することで、どのようにcandidateを探すか指定できるようにする、なんて機能も紹介されました(ドキュメントを読む限りこの機能はまだHEADに入ってない?)。
77 | 例えば、Hoogleを使ってValid Hole Fitsを探したいとき、次のように書くことで検索対象を`Control.Applicative`に限定する、といったことをできるようしてくれます。
78 |
79 | ```haskell
80 | g :: [a] -> [[a]]
81 | g = _{hoogleLookup "+Control.Applicative"}
82 | ```
83 |
84 | Valid Hole Fitsの検索方法をその場で微調整したい、というときに使うものですね。
85 |
86 | ## Visible dependent quantification
87 |
88 | - 発表者: Ryan Scott *Indiana University at Bloomington, USA*
89 | - 該当のMerge Request: [!378](https://gitlab.haskell.org/ghc/ghc/merge_requests/378)
90 | - 該当のGHC Proposal: [0081-forall-arrow](https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0081-forall-arrow.rst)
91 |
92 | タイトルのとおり、「Visible dependent quantification」という機能の紹介です。
93 |
94 | 最近のバージョンのGHCiにおける`:kind`コマンドは、次のような、GHCがサポートしていない構文の型注釈を出力することがあります。
95 | 例えば
96 |
97 | ```haskell
98 | > :set -XKindSignatures
99 | > :set -XPolyKinds
100 | > data SomeType k (a :: k)
101 | > :kind SomeType
102 | SomeType :: forall k -> k -> *
103 | ```
104 |
105 | における、`SomeType :: forall k -> k -> *`の`forall k ->`という部分です。
106 | 現在のHaskellで`forall k`などと書くときは、必ず
107 |
108 | ```haskell
109 | SomeType :: forall k. k -> *
110 | ```
111 |
112 | といった具合に、ピリオドで区切った構文になります。
113 | ところが先ほどの`:kind`の出力では、`forall k ->`とあるとおり、`forall k`に(型ではなく、カインドとしての)関数を表す`->`が使われています。
114 | 「Visible dependent quantification」はまさにこれを、`:kind`コマンドによって出力される構文だけではなく、ユーザーが直接書ける構文にしよう、というものです。
115 | GHCに「依存型」という機能を加える「Dependent Haskell」にも必要な機能だそうです。
116 | 私自身はこの機能を使う機会がちょっと思い浮かばなかったので省略しますが、より詳しい解説は発表者である[Ryan自身による記事(英語)](https://ryanglscott.github.io/2019/03/15/visible-dependent-quantification-in-haskell/)をご覧ください。何が「Visible」でどう「Dependent」なのかわかるはずです。
117 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2019/hiw-ghc8.8.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: HIW 2019で発表された、GHC 8.8で導入された機能
3 | subHeading: ~HIW 2019参加レポート その1~
4 | headingBackgroundImage: ../../img/background.png
5 | headingDivClass: post-heading
6 | author: Yuji Yamamoto
7 | postedBy: Yuji Yamamoto(@igrep)
8 | date: September 11, 2019
9 | tags: GHC, Haskell Implementors' Workshop
10 | ...
11 | ---
12 |
13 | こんにちは。
14 | 今回からいくつか、「[Haskell Implementors' Workshop 2019](https://icfp19.sigplan.org/home/hiw-2019#About)」に私が先月参加した際のレポートとして、印象深い発表をテーマごとに分けた短い記事を執筆します。
15 | 最近公開された[GHC 8.8](https://www.haskell.org/ghc/download_ghc_8_8_1.html)の話はもちろん、未来のGHCやその他のHaskellの処理系を知るのによいイベントでしたので、その一部だけでも伝われば幸いです。
16 |
17 | # そもそもHaskell Implementors' Workshop (HIW)とは?
18 |
19 | シリーズ(?)第1回目なので、簡単にHIWそのものについて紹介しておきましょう。
20 | HIWは、[ICFP (International Conference on Functional Programming)](https://icfp19.sigplan.org/home)という関数型プログラミングについての国際会議に併設された、Haskellの実装者のためのワークショップです。
21 | 名前の通り、GHCをはじめとするHaskellの処理系(あるいは、Haskellで実装された言語処理系)の実装に関する発表だけでなく、かなり緩いテーマのLightning Talkの時間があったり、GHCの将来の方向性について自由に議論する時間もあったりしました。
22 |
23 | 今回はそのうち、掲題のとおり「HIW 2019で発表された、GHC 8.8で導入された機能」を紹介します。まずは「HIE files in GHC 8.8」から。
24 |
25 | # HIE files in GHC 8.8
26 |
27 | 発表者: Zubin Duggal, Matthew Pickering *University of Bristol*
28 |
29 | GHC 8.8で新たに追加された、HIE(「Haskell Interface Extended」の略と思われます)ファイルについての発表です。
30 | コンパイル時にGHCが得たモジュールの情報を、[Haskell IDE Engine](https://github.com/haskell/haskell-ide-engine)などのIDEのバックエンドが再利用しやすい形で出力する機能です。
31 | 従来Haskell IDE Engine(その裏で使われているghc-mod)や[ghcid](https://github.com/ndmitchell/ghcid)、[intero](https://github.com/chrisdone/intero)などの、「IDEバックエンド」(エディターが入力の補完や入力したソースコードにおけるエラーを表示する際に通信するソフトウェア)は、自前でGHC APIやGHCiを呼ぶことで、型チェックしたり定義ジャンプに必要な位置情報を収集したりしていたのですが、そうした情報の収集をすべてGHC自身がHIEファイルを出力することで賄えるようになる、ということです。
32 |
33 | 私は従来開発中、`stack test --pedantic --file-watch`などとNeovimのターミナル機能で実行して実行ファイルをビルドしつつ、HIEにエラーの表示や入力の補完をさせていたのですが、その際も二重にソースコードが解析されていたんですね!
34 | 私がそのようにわざわざ`stack test`とHIEを並行して実行させているのは、HIEがしばしばフリーズしてしまったり(Neovimごと再起動すれば直ることも多いんですが...😰)、HIEだけでは実行ファイルの作成やテストの実行ができない、という理由があるためです。
35 | `stack test`だけでHIEファイルが生成されるようになれば、エラーに関する情報やソースコードの解析結果といった情報が一元化されるので、より安定的に、より少ないリソースでHIEが使えるようになるでしょう。本家Haskell IDE Engineがサポートする日が楽しみです。
36 |
37 | この、HIEファイルを利用するアプリケーションの例も紹介されました。
38 | [hie-lsp](https://github.com/wz1000/hie-lsp)という小さなLanguage Server Protocolの実装に加え、[hie-lsif](https://github.com/mpickering/hie-lsif)という、HIEファイルから「[Language Server Index Format (LSIF)](https://github.com/microsoft/language-server-protocol/blob/master/indexFormat/specification.md)」形式のファイルを作成するコマンドが印象的でした。
39 | このLSIFというファイルは、例えばGitHubのリポジトリ上でブラウザからソースコードを閲覧する際にも、定義ジャンプといった便利な機能を使えるようにするためのものです。リポジトリに置いたソースコードを処理系がどのように解釈したかを保存しておくことで、Language Serverはじめ処理系を実行することなく利用できるようにするものだそうです。
40 | 現状は仕様策定中なためか、実際にLSIFを解釈するアプリケーションは見つかりませんでしたが、今後の活用に期待が高まりますね。
41 |
42 | 加えて、HIEファイルが将来的にサポートしたい機能などについても発表されました。
43 |
44 | - 型クラスのインスタンスが、具体的にどの型のインスタンスとして解決されたかの出力
45 | - 定義ジャンプしたときに、型クラス自身の宣言ではなく、実装に飛べるようにするため
46 | - 従来GHCが分割コンパイルをサポートするために、モジュールの依存情報を出力していた「インターフェースファイル(`.hi`という拡張子で出力されているあのファイル)」との統合
47 | - すべての型推論の結果
48 |
49 | # GHC status report
50 |
51 | 発表者: Simon Peyton Jones *Microsoft, UK*
52 |
53 | GitLabへの移行やHadrianと呼ばれる新しいビルドシステムの導入など、インフラ周りでいろいろ変更があったこともあり、遅れてしまいましたがGHC 8.8がもうすぐ出るよ、という内容の発表でした(発表当時。もう[GHC 8.8はリリースされています](https://www.haskell.org/ghc/blog/20190825-ghc-8.8.1-released.html))。
54 |
55 | 言及された主な追加機能は以下のとおりです。
56 |
57 | - [`TypeApplications`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#extension-TypeApplications)という言語拡張が、型変数だけでなくカインド変数に対しても適用できるようになりました。
58 | 正直に言って、個人的に使いどころがまだまだなさそうな機能ではありますが...。
59 | - [`ScopedTypeVariables`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#extension-ScopedTypeVariables)という言語拡張を使った場合に、パターンマッチした変数に型注釈を付けることができるようになる、という機能がありまして、これが拡張されました。
60 | 具体的には、従来下記のように書くことで、関数自体の型注釈にある型変数`a`と、パターンマッチした変数`x`に型注釈した`b`が等しくなるように書くことができたのを、
61 |
62 | ```haskell
63 | f :: forall a. Maybe a -> Int
64 | f (Just (x :: b)) = {- ... -}
65 | ```
66 |
67 | さらに拡張して、関数自体の型注釈にある型変数**ではない**`Int`と、パターンマッチした変数`x`に型注釈した`b`が等しくなるように書くことができるようにした、という拡張です。
68 | あたかも型変数でパターンマッチしているかのようですね。
69 |
70 | ```haskell
71 | f :: Maybe Int -> Int
72 | f (Just (x :: b)) = {- ... -}
73 | ```
74 |
75 | 一体何の役に立つの?とも思いましたが、[この修正に向けた提案](https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0128-scoped-type-variables-types.rst#128motivation)曰く、
76 |
77 | ```haskell
78 | f :: ReallyReallyReallyReallyLongTypeName -> T
79 | f (x :: a) = … (read "" :: a) …
80 | ```
81 |
82 | と書くことで、長い型名に対して別名を付けることができるようになる、というメリットがあるそうです。なるほど💡
83 |
84 | # とりあえず今回はここまで
85 |
86 | テーマを絞って短い記事にした方がSEO的にいいんじゃないかと思いまして、今回は敢えて紹介する発表を絞りました。
87 | 今後は下記のテーマについて紹介する予定です。
88 |
89 | - HIW 2019で発表された、これからのGHCに入るであろう機能
90 | - HIW 2019で発表された、GHC以外の言語処理系
91 |
92 | また、HIWと同じくICFP 2019に併設して開催された、[Haskell Symposium 2019](https://icfp19.sigplan.org/home/haskellsymp-2019)の発表についても別途共有する予定です。
93 | 乞うご期待。
94 | hask(\_ \_)eller
95 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2019/hiw-gibbon.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: HIW 2019で発表された、Gibbonコンパイラーについて
3 | subHeading: ~HIW 2019参加レポート その3~
4 | headingBackgroundImage: ../../img/background.png
5 | headingDivClass: post-heading
6 | author: Yuji Yamamoto
7 | postedBy: Yuji Yamamoto(@igrep)
8 | date: September 28, 2019
9 | tags: Haskell Implementors' Workshop
10 | ...
11 | ---
12 |
13 | [前回](/posts/2019/hiw-ghc-future.html)から引き続き、[Haskell Implementors' Workshop 2019](https://icfp19.sigplan.org/home/hiw-2019#About)への参加レポートとして、私の印象に残った発表を紹介します。
14 | 今回は、[Gibbon](http://iu-parfunc.github.io/gibbon/)という、GHC以外のHaskell(の、サブセット)の処理系についての発表です。
15 |
16 | # The Gibbon Compiler: Accelerating a small subset of Haskell
17 |
18 | 発表者: Ryan R. Newton *Indiana University*, Michael Vollmer *Indiana University, USA*, Chaitanya Koparkar *Indiana University*
19 |
20 | Gibbonは最適化の手法を研究するために作られたコンパイラーです。
21 | 具体的には、我々(特にHaskeller)がよく使う、木構造全体に対する処理の最適化です。
22 |
23 | こうした木構造のデータは、通常ポインターを使ってメモリー内にバラバラに格納されますが、Gibbonによる最適化を行うと、実際にプログラムがどのような順番で木を処理しているのか解析して、(元のデータ構造を配列に変換した上で)その順番に並べられた配列として処理するコードに変換する、という大胆な変換を行います。
24 | 図にするとこんなイメージでしょうか?
25 |
26 | 
27 |
28 | 👆のような木構造があったとして、
29 |
30 | 
31 |
32 | 👆における、赤い線の順番(行きがけ順)にアクセスする関数があったとします。
33 | 適当にHaskellの再帰関数として書くと、👇こういうコードです。
34 |
35 | ```haskell
36 | data Tree = Node Char (Maybe Tree) (Maybe Tree) deriving Show
37 |
38 | tree :: Tree
39 | tree =
40 | Node 'A'
41 | ( Just
42 | ( Node 'B'
43 | (Just (Node 'D' Nothing Nothing))
44 | (Just (Node 'E' Nothing Nothing))
45 | )
46 | )
47 | ( Just
48 | ( Node 'C'
49 | (Just (Node 'F' Nothing Nothing))
50 | (Just (Node 'G' Nothing Nothing))
51 | )
52 | )
53 |
54 | preOrder :: (Char -> IO ()) -> Tree -> IO ()
55 | preOrder access (Node char mLeft mRight) = do
56 | access char
57 |
58 | case mLeft of
59 | Just left -> preOrder access left
60 | Nothing -> return ()
61 |
62 | case mRight of
63 | Just right -> preOrder access right
64 | Nothing -> return ()
65 | ```
66 |
67 | Gibbonはこの関数と、それが処理する木構造を解析して、
68 |
69 | 
70 |
71 | 👆のような、ただの配列(とそれに対する関数)にまとめて変換してしまう、というのです!
72 |
73 | 現代のコンピューターは、このような配列の要素にまとめてアクセス処理する方が、ポインターをたどって各要素を処理するより、たいてい遙かに速いです。
74 | Gibbonはこの特性を活かすべく、我々Haskellerが好んで使うような、ポインターだらけの木構造を可能な限り配列に変換することで、要素をまとめて処理する(traverseする)演算の最適化を図るコンパイラーです。
75 |
76 | ちなみに、元の木に対するノードの追加に相当する処理は、新しいノードに対するポインターを書き込む処理に変換するそうです。
77 | なので何度も追加を繰り返すと、あまり恩恵が受けられなくなってしまいそうです。
78 |
79 | なかなか興味深いアイディアですが、個人的に聞きそびれた疑問が2つあります。
80 | 一つは、そもそも木構造を定義するような状況というのは、いろいろな順番でアクセスしたいし、新しい要素の追加も繰り返し行いたいケースではないでしょうか?
81 | 例えば[unordered-containers](http://hackage.haskell.org/package/unordered-containers)にある`HashMap`型は探索木を使った頻繁に使われるデータ構造ですが、`HashMap`を使う場合に行う処理の多くは、ランダムアクセスや要素の追加・削除でしょう。
82 |
83 | なので、Gibbonが最適化したい「木構造」というのは、どちらかというと探索木のような木ではなく、構文木のような、要素をまとめて処理することを前提とした木のことなのかもしれません。
84 | 確かに人間が書く言語の構文木程度であれば、すべてメモリー上で処理できる程度のサイズに収まる(という想定でなければコンパイラー作りがものすごく難しくなる)でしょうし、構文木の処理を高速化できれば、遅い遅いと言われるGHCのコンパイル速度も高められるはずです。それはそれでありがたい。
85 |
86 | もう一つは、これまた例えば`HashMap`型のような木をベースにした連想配列も、配列ベースのハッシュテーブルに変換することができるのでしょうか?
87 | もしそうだとすると、ランダムアクセスに対する計算量のオーダーもO(log n)からO(1)に変わるわけですし、要素をまとめて処理する以外の演算についても劇的な改善が見込めるかもしれません。
88 | もちろんこれも先ほどの推測が正しければ無意味な想像ですが、夢のある話ですね。
89 |
90 | Gibbonは将来的には、`Packed`という型クラスを提供することで、GHC本体への統合も視野に入れているそうです。
91 | `Packed`を実装した型は、値をどのように配列に変換するのか定義することで、Gibbonによる最適化のためのヒントを与えることができます。
92 |
93 | 参考: [木構造 (データ構造) - Wikipedia](https://ja.wikipedia.org/w/index.php?title=%E6%9C%A8%E6%A7%8B%E9%80%A0_\(%E3%83%87%E3%83%BC%E3%82%BF%E6%A7%8B%E9%80%A0\)&oldid=72655479)
94 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2019/string-gap-for-heredoc-like.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskell でも heredoc がしたい
3 | headingBackgroundImage: ../../img/post-bg.jpg
4 | headingDivClass: post-heading
5 | subHeading: string gap の紹介
6 | author: mizunashi_mana
7 | postedBy: mizunashi_mana
8 | tags: heredoc, CPP
9 | date: April 17, 2019
10 | ...
11 | ---
12 |
13 | 多くの言語では, here document (heredoc) という言語機能が搭載されています.これは,複数行の文字列をコード中に文字列リテラルとして埋め込める機能です.今日は heredoc ほど使い勝手がよくないものの,長い文字列を埋め込める, Haskell 標準の string gap という機能を紹介したいと思います.
14 |
15 | ## string gap
16 |
17 | bash では,複数行の文字列を,次の記法で埋め込むことができます:
18 |
19 | ```bash
20 | echo "$(cat <Yuji Yamamoto(@igrep)
7 | date: July 8, 2019
8 | tags:
9 | ...
10 | ---
11 |
12 | 現職でHaskellを仕事で書き始めるようになってからというもの、度々小さなパッケージをリリースするようになりました。
13 | 敢えてパッケージにするほどのものでもなさそうなぐらい小さなものが多いですが、もし再利用したくなったらな、という気持ちで書いております。
14 |
15 | # なに作ったか
16 |
17 | [strip-ansi-escape](http://hackage.haskell.org/package/strip-ansi-escape)というパッケージです。
18 | 今回もメインの処理は100行にも満たないような小さなもので、また用途もニッチです。
19 | 具体的には、名前のとおり[ANSIエスケープコード](https://en.wikipedia.org/wiki/ANSI_escape_code)を文字列から取り除く、ただそれだけです。
20 | 使い方も極めてシンプル:
21 |
22 | ```haskell
23 | ghci> import Data.String.AnsiEscapeCodes.Strip.Text
24 |
25 | -- 現状Text型向けにしか作っていないため、OverloadedStringsを有効にした方が使いやすい
26 | ghci> :set -XOverloadedStrings
27 | ghci> import Data.Text
28 |
29 | -- 出力すると下線付きで "hello" と表示されるANSIエスケープコード付きの文字列
30 | ghci> "\x001B[4mhello\x001B[0m"
31 | "\ESC[4mhello\ESC[0m"
32 |
33 | ghci> stripAnsiEscapeCodes "\x001B[4mhello\x001B[0m"
34 | "hello"
35 | ```
36 |
37 | # なぜ作ったか
38 |
39 | 通常我々がANSIエスケープコードを扱うときは、**ユーザーのために**端末に文字列を分かりやすく表示したいときで、それをプログラムで再利用することは想定していません。
40 | そのためANSIエスケープコードを出力できるアプリケーションは、大抵の場合出力しないよう設定できる(あるいは、出力先がttyでないことを検出して出力しない)ようになっています。
41 | なので、プログラムがANSIエスケープコードの混ざった文字列を扱わざるを得ない、という事態は、何かがおかしい事態だと言えるでしょう。
42 |
43 | 一体どういう事態なのかというと、それは私がずっと開発中の、対話的Haskell入門コンテンツ --- [「失敗しながら学ぶHaskell入門」](https://github.com/haskell-jp/makeMistakesToLearnHaskell) --- で出遭った事態でした。
44 | 「失敗しながら学ぶHaskell入門」(以下、英語名を略して「mmlh」と呼びます)では、ユーザーが書いたHaskellのソースコードを受け取って、GHCにコンパイルさせることで、型エラーなどのエラーメッセージを取得しています。
45 | 当初からmmlhはそれを簡単にパースしてユーザーへのヒントを出すのに使ったり、ユーザーにそのまま表示したりするのに使うため、`-fdiagnostics-color=always`というオプションをGHCに渡していました。
46 | これは、エラーメッセージに色を着けるようになったGHC 8.2から導入されたオプションで、「エラーメッセージに必ず(ANSIエスケープコードを使って)色を着ける」というものです。
47 | GHCが出すエラーメッセージを「簡単にパース」しつつ「ユーザーにそのまま表示」する、という2つの要件を満たすためには、このオプションを利用して、強制的にエラーメッセージに色を着ける必要がありました。
48 |
49 | さらに最近、GHCが出したエラーメッセージをファイルに保存して、[GitHubで閲覧できるようにする](https://github.com/haskell-jp/makeMistakesToLearnHaskell/issues/101)(正確には、閲覧して各行にコメントできるようにする)、という機能も追加した結果、ANSIエスケープコードを取り除かざるを得なくなってしまったのです。
50 | というのも、`-fdiagnostics-color=always`を有効にしている限り、GHCは必ずANSIエスケープコードをエラーメッセージに混ぜるので、ファイルに保存してGitHub上で表示する際、下記のように余計な文字として混ざってしまい、エラーメッセージが読みづらくなってしまうためです。
51 |
52 | ```
53 | �[;1m16.hs:19:18: �[;1m�[31merror:�[0m�[0m�[;1m�[0m�[0m�[;1m
54 | • No instance for (Num ([Char], String))
55 | arising from a use of ‘countWords’
56 | • In the expression: countWords (concat wordsList)
57 | In an equation for ‘countMap’:
58 | countMap = countWords (concat wordsList)
59 | In the expression:
60 | do paths <- getArgs
61 | wordsList <- for paths scrapeWords
62 | let countMap = countWords (concat wordsList)
63 | for_ (toList countMap) catCount�[0m�[0m
64 | �[;1m�[34m |�[0m�[0m
65 | �[;1m�[34m19 |�[0m�[0m let countMap = �[;1m�[31mcountWords (concat wordsList)�[0m�[0m
66 | �[;1m�[34m |�[0m�[0m�[;1m�[31m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^�[0m�[0m
67 | �[0m�[0m�[0m
68 | ```
69 |
70 | `-fdiagnostics-color=always`を有効にしなければこんな問題は起こらないのですが、そうすると今度はユーザーにエラーメッセージを表示させる際、色が着かなくなってしまいます。
71 | せっかくGHC 8.2以降を使っているのに色つきのエラーメッセージが見られないのは残念ですよね。
72 | GHCを2回実行することで、ユーザーに表示する用のエラーメッセージとファイルに保存する用のエラーメッセージを分けることもできますが、それでは効率が悪いでしょうし。
73 |
74 | そんなわけで、GHCが出力するエラーメッセージを**ユーザーに端末上で表示する用途と、ANSIエスケープコードを解釈しない箇所で表示する用途**、両方に使用したくなったため、今回敢えてANSIエスケープコードを取り除くライブラリーを作りました。
75 | もし他に同じような事態に出遭った方がいらっしゃいましたら、試してみてください🙏
76 |
77 | # 最近のmmlh
78 |
79 | ついでにここ数ヶ月弊社でやっている、mmlhを使った社内勉強会のお話も書こうかと思いましたが、やっぱり社内でのことなんで、[会社のブログ](https://eng-blog.iij.ad.jp/)に書くことにします。
80 | ~~多分今週中には上げますので乞うご期待!~~
81 | ⬇️大分遅くなってしまいましたが公開しました!
82 |
83 | [Haskell社内勉強会とHaskell学習ツールの紹介 | IIJ Engineers Blog](https://eng-blog.iij.ad.jp/archives/3467)
84 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2019/unicode-show.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 日本語をshowしてうまく表示されなかったら
3 | subHeading: unicode-showの紹介(と、pretty-simpleを少し)
4 | headingBackgroundImage: ../../img/background.png
5 | headingDivClass: post-heading
6 | author: YAMAMOTO Yuji
7 | postedBy: YAMAMOTO Yuji(@igrep)
8 | date: December 22, 2019
9 | tags: 日本語
10 | ...
11 | ---
12 |
13 | # ℹ️この記事は🎄
14 |
15 | この記事は、[Haskell Advent Calendar 2019](https://qiita.com/advent-calendar/2019/haskell) 22日目の記事です。
16 | 例年どおりタイプセーフプリキュア!の話をするつもりでしたが、ネタが実装できなかったので[unicode-show](http://hackage.haskell.org/package/unicode-show)の話をします[^precure]。
17 | まぁ、こちらの方がみなさんにとっては有益でしょうし🙃
18 |
19 | [^precure]: 例年どおりですとプリキュアAdvent Calendarと同時投稿をしている予定でしたが、例年参加者が減っていたこともあり、今年はプリキュアAdvent Calendarはなくなってしまいました😞
20 |
21 | # 日本語(などの)話者がHaskellを始めるとあるある
22 |
23 | GHCiに日本語を入力したり...
24 |
25 | ```haskell
26 | ghci> "みんなで幸せゲットだよ!"
27 | "\12415\12435\12394\12391\24184\12379\12466\12483\12488\12384\12424\65281"
28 | ```
29 |
30 | 日本語を`print`したり...
31 |
32 | ```haskell
33 | ghci> print "私、堪忍袋の緒が切れました!"
34 | "\31169\12289\22570\24525\34955\12398\32210\12364\20999\12428\12414\12375\12383\65281"
35 | ```
36 |
37 | 日本語を`show`したり...
38 |
39 | ```haskell
40 | ghci> iimashita x = "今、" ++ show x ++ "って言いました!?"
41 | ghci> putStrLn (iimashita "ハスケル")
42 | 今、"\12495\12473\12465\12523"って言いました!?
43 | ```
44 |
45 | すると、日本語の大半が変な文字列に変わってしまいました😥。
46 |
47 | へ... 変な文字列じゃないし!エスケープシーケンスに変換しただけだから!
48 |
49 | これは、Haskell標準における`show`関数の残念な仕様です。
50 | `show`関数に文字列を渡すと、ダブルクォートで囲った上で、ASCII範囲外の文字列や、ASCIIの非表示文字などをエスケープシーケンスに変換して返します。
51 | これは、`show`関数をデバッグで使用した際、指定した文字列にどんな文字が含まれているか、簡単にわかるようにするための仕様です。
52 | 文字の文字コードを表示すれば、NULL文字や制御文字、ゼロ幅文字、特殊なスペースなど、視認しにくいおかしな文字が含まれていても、一目でわかるのです。
53 |
54 | しかしこれは日本語話者である我々にとって、少なくとも日本語の文字に関しては「余計なお世話」です。
55 | NULL文字やASCIIの制御文字といった本来画面に表示することがない文字列ならともかく、ASCII範囲外の文字列すべてをエスケープしてしまうのはやり過ぎでしょう。
56 | 現代はUnicodeがあるおかげで、日本語に限らずともASCII範囲外の文字を扱うのは当たり前になりましたから。
57 |
58 | # 🌐unicode-showを使おう
59 |
60 | そこで便利なのが[unicode-show](http://hackage.haskell.org/package/unicode-show)です。
61 | unicode-showの`ushow`関数は、`show`がエスケープシーケンスに変換した日本語などの文字列を、元の文字列に戻してくれます。
62 | なので、新しい型クラスを定義する必要もなく、そのまま`Show`型クラスのインスタンスを再利用できるのです。
63 |
64 | 早速先ほどの`show`を使った例に適用してみましょう。
65 |
66 | まずは👇のコマンドでインストールして、GHCiを起動します。
67 |
68 | ```bash
69 | stack build unicode-show
70 | stack exec ghci
71 |
72 | # あるいは、最近のcabalを使っている場合は...
73 | cabal v2-install --lib unicode-show
74 | cabal v2-repl -b unicode-show
75 | ```
76 |
77 | `Text.Show.Unicode`モジュールを`import`して`show`を使っている箇所を`ushow`に変えれば、お望みどおりの挙動になります。
78 |
79 | ```haskell
80 | ghci> import Text.Show.Unicode
81 | ghci> iimashita x = "今、" ++ ushow x ++ "って言いました!?"
82 | ghci> putStrLn (iimashita "ハスケル")
83 | 今、"ハスケル"って言いました!?
84 | ```
85 |
86 | わくわくもんですね!
87 |
88 | `print`の例も、`uprint`に変えれば🆗です。
89 |
90 | ```haskell
91 | ghci> uprint "私、堪忍袋の緒が切れました!"
92 | "私、堪忍袋の緒が切れました!"
93 | ```
94 |
95 | ウルトラハッピーですね!!
96 |
97 | さらに、次のコマンドをGHCiに入力すれば、GHCiに直接入力した日本語文字列もそのまま表示されるようになります。
98 |
99 | ```haskell
100 | ghci> :set -interactive-print=uprint
101 | ghci> "みんなで幸せゲットだよ!"
102 | "みんなで幸せゲットだよ!"
103 | ```
104 |
105 | カンペキ✨
106 |
107 | えっ、常に`uprint`したいからいちいち`:set -interactive-print=uprint`するのが面倒くさい?
108 | そんなあなたは👇を`~/.ghci`に書くことけって~いでしょう。
109 |
110 | ```haskell
111 | import qualified Text.Show.Unicode
112 | :set -interactive-print=Text.Show.Unicode.uprint
113 | ```
114 |
115 | # unicode-showの最近の修正
116 |
117 | そんなunicode-showですが、残念ながら一昨年、作者である村主崇行さんが亡くなってしまいました[^nushio]。
118 | 日本に住むHaskellerをサポートする日本Haskellユーザーグループとしては、このパッケージをメンテナンスし続けることに大きな意義があると判断し、私はこのパッケージを[Haskell-jp](https://github.com/haskell-jp/)のGitHubリポジトリーでメンテナンスすることにしました。
119 | 以下がそのリポジトリーです。
120 |
121 | [^nushio]: 村主崇行さんは「[すごいHaskellたのしく学ぼう!](https://shop.ohmsha.co.jp/shopdetail/000000001926/)」の翻訳を担当されるなど、unicode-show以外にも日本のHaskell界に多大な功績をもたらした方でした。
122 |
123 |
124 |
125 | といっても、メンテナーの名前や`LICENSE`ファイルを書き換えて最新版をアップロードして以降特に何もしていなかったのですが([バグはあるけど直すのも難しそう](https://github.com/nushio3/unicode-show/issues/2)だし、概ね使えるし)、なんと先日、Pull requestが来ました!
126 |
127 | [Do not show values eagerly by Kaiepi · Pull Request #4 · haskell-jp/unicode-show](https://github.com/haskell-jp/unicode-show/pull/4)
128 |
129 | この修正を適用する前のunicode-showは、文字列全体を評価してからエスケープシーケンスを元に戻す、という挙動だったため、長い文字列を与えた場合や無限の長さの文字列を与えた場合に、なかなか(あるいは永遠に)結果が返ってこないという問題がありました。
130 |
131 | ```haskell
132 | ghci> uprint (repeat "ああああ!")
133 | -- 何も表示されず、Ctrl + C を押すまで処理が返らない
134 | ```
135 |
136 | 修正後はちゃんと遅延評価を利用することで、無限の長さの文字列でも少しずつ変換することができます。
137 |
138 | ```haskell
139 | ghci> uprint (repeat "ああああ!")
140 | ["ああああ!","ああああ!", ... "ああああ!","ああInterrupted.
141 | -- Ctrl + Cを押すまで出力し続ける
142 | ```
143 |
144 | 今日記事にした一番の理由はこの話をするためです。
145 | [Kaiepi](https://github.com/Kaiepi)さんありがとうございます!
146 | 先ほどリリースしました!🎉
147 |
148 |
149 |
150 | # (番外編)pretty-simpleも使おう
151 |
152 | 時間がないので詳しくは省略しますが、実は[pretty-simple](http://hackage.haskell.org/package/pretty-simple)というパッケージを使えば、日本語をそのまま出力するのに加えて、プリティープリントできます。
153 |
154 | ```haskell
155 | ghci> import Text.Pretty.Simple
156 | ghci> pPrint ["きーらーめーくー♪", "ほーしーの力でー♪", "あこがーれのー♪", "わーたーし描くよー♪"]
157 | [ "きーらーめーくー♪"
158 | , "ほーしーの力でー♪"
159 | , "あこがーれのー♪"
160 | , "わーたーし描くよー♪"
161 | ]
162 | ```
163 |
164 | 例ではわかりづらいですが、ちゃんと色も着けてくれます!
165 | それでは2020年も、Happy Haskell Hacking🎁
166 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2020/haskell-casually-at-work.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskellを業務で使う、カジュアルに
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | author: takenobu.hs
6 | postedBy: takenobu.hs
7 | date: April 26, 2020
8 | tags:
9 | ...
10 | ---
11 |
12 | はじめに
13 | =======
14 |
15 | この記事では、Haskellを業務でカジュアルに使う観点やヒントについて、簡単に紹介します。
16 |
17 | Haskellを業務で使える局面は、以下のようにいくつか考えられます。
18 |
19 | 1. 「プロダクト」の開発用言語として、Haskellを使う
20 | 2. 「作業」の支援・加速用に、Haskellを使う
21 | 3. 「思考」の支援・加速用に、Haskellを使う
22 |
23 | つまり、プロダクトの開発用言語としてHaskellを用いない業務形態においても、上記2や3のケースとして、Haskellを使用できます。すなわち、Haskellは幅広い局面でカジュアルに、つまり気軽に手軽に使用できます。
24 |
25 | 本記事では、特に、上記の2と3について、いくつかの観点やヒントや例を紹介します。
26 |
27 | なお、上記は、Haskellを用いる場合には限りません。Python, Perl, Ruby, Rust, Scala, OCaml, Clojure, Go, Elixir, ... といった、様々なプログラミング言語に置き換えて本記事を解釈してもらって構いません。
28 |
29 |
30 | ------
31 |
32 | 🔧「作業」の支援・加速に、Haskellを使う
33 | =====================================
34 |
35 | Haskell(を含むプログラミング言語)は、開発などの日常業務において、「作業」の支援・加速用に使うことが出来ます。
36 |
37 | つまり、電卓やExcelなどのように、Haskellを日常ツールの一つとして使えます。
38 |
39 | 特に、直近の業務作業を加速するために、書き捨てのツールを高品質で素早く欲しい場合や、ちょっとした対話ツールを欲しい場合などにも、Haskellを便利に活用できます。
40 |
41 | 例えば具体的には、以下の場合にHaskellを便利に使えます。
42 |
43 | * テストデータ生成
44 | * パーサー
45 | * 階層データ処理
46 | * 高機能電卓
47 |
48 | 以下、それぞれについて簡単に紹介します。
49 |
50 |
51 | ## テストデータ生成
52 |
53 | 例えば、解析事案が発生し、至急10分程度でテストデータを複数用意したい、というような場合に、Haskellでデータを生成させることは有効です。
54 |
55 | Haskellは、関数合成や部分適用や高階関数や多相関数などの言語的な特徴により、小さな関数を組み合わせて、より大きな関数として作り上げることが容易です。
56 |
57 | 対話環境(REPL)であるGHCiを用いて、それら小さな関数を素早く高品質に確認した上で、徐々に大きな関数として組み合わせることにより、高品質な結果を素早く得ることがでできます。
58 |
59 | 特にバイナリデータや複雑なデータを、一刻も早く高品質に生成することが重要な局面で、Haskellは威力を発揮します。
60 |
61 |
62 | ## パーサー
63 |
64 | 日常業務において、各種ログなどのデータを解析したい局面は頻繁に有ります。
65 | 単純なデータであれば、grepコマンドやPerlなどの正規表現を用いて手早く仕事を済ませることも出来ます。
66 |
67 | しかし、データの構造が複雑であったり再帰的な構造である場合には、正規表現をデバッグするよりも、Haskellで思い切ってパーサーを書いてしまう方が手早く済ませられることがあります。
68 |
69 | Haskellでは、関数の組み立てが容易であることやdo記法といった言語的な特徴を活かし、簡潔にパーサーを記述することができます。
70 | 言語的な特徴を活かした便利なパーサーコンビネータ関連のライブラリ([`Parsec`](https://hackage.haskell.org/package/parsec)や[`Megaparsec`](https://hackage.haskell.org/package/megaparsec)や[`replace-attoparsec`](https://hackage.haskell.org/package/replace-attoparsec)など)が豊富に存在します。
71 |
72 | 一度パーサーの骨格を用意してしまえば、流用は容易であるため、強力な日常ツールとしてHaskellを便利に使用できます。
73 |
74 |
75 | ## 階層データ処理
76 |
77 | 例えばモジュールの構造に対応したデータのように、データが再帰的・階層的に表現されている場合は多くあります。
78 |
79 | Haskellは、代数的データ型を用いて再帰的なデータ構造を簡潔に表現できます。また、簡潔なパターンマッチの記法と再帰的な関数により、これらの処理を容易に記述できる傾向にあります。
80 |
81 | もちろん、この再帰的なデータ構造も、コンパイル時の静的な型チェックの対象となるため、多くの不用意なミスを事前に抽出できます。
82 |
83 | 素早く、非常に高品質にデータ処理を行うことが重要な局面で、Haskellは有効に機能します。
84 |
85 |
86 | ## 高機能電卓
87 |
88 | 日常業務において、なんらかの変換テーブルや、計算式、定数値などの値を、散発的に直ちに得たい局面があります。
89 | その都度、電卓で計算したり、Excelなどの計算フォームを用意することで、手軽に業務を済ませられる場合もあります。
90 |
91 | しかし、繰り返し必要となる計算式や、ある程度複雑な計算であれば、これらの計算式などを、Haskellの関数群として定義しておき、対話環境GHCiから用いることで、使い勝手良く素早く値を得ることができます。
92 |
93 | 数値や対話操作などを補助する便利なライブラリ([`Numeric`](https://hackage.haskell.org/package/base/docs/Numeric.html)や[`Data.Bits`](https://hackage.haskell.org/package/base/docs/Data-Bits.html)や[`Data.GHex`](http://hackage.haskell.org/package/ghci-hexcalc/docs/Data-GHex.html))や言語拡張([`BinaryLiterals`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#binary-integer-literals)や[`NumericUnderscores`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#numeric-underscores))などが豊富に存在します。
94 |
95 | Haskellにおける関数の組み立てが容易な特徴は、対話環境における対話的な操作との相性が良いため、試行錯誤的な計算作業にも有用です。
96 |
97 |
98 | ## その他
99 |
100 | 他にも、定型的なファイル処理やCLIコマンドやDSLの構築などを、Haskellを用いて便利に実現出来ます。
101 | 手元に各種雛形を蓄積していると、作業の素早さと正確さが求められる場合に、有益でしょう。
102 |
103 | もちろん、これらはHaskellに限らず、多くのプログラミング言語にも言えます。
104 |
105 | Haskellは、型システムに守られながら、関数を容易に組み立てられる特徴を持ちます。また、代数的データ型とパターンマッチの特徴により、直感的・シンプルで高品質なデータ表現・処理が可能です。さらに、GHCiを用いる対話操作により、日常作業を高品質かつ手早く行えます。
106 |
107 | Haskellは、(型システムの高度な機能などを使わない)基本的な機能のみにおいても、日常業務において有効に活用できるツールの一つです。
108 |
109 |
110 | ------
111 |
112 | 💡「思考」の支援・加速に、Haskellを使う
113 | =====================================
114 |
115 | Haskell(を含むプログラミング言語)は、開発などの日常業務において、「思考」の支援・加速用にも使うことが出来ます。
116 |
117 | つまり、紙と鉛筆などのように、Haskellを思考ツールの一つとして使えます。
118 |
119 | 特に、試行錯誤的な思考フェーズや、探索フェーズにおいて、思考を整理・加速する場合などに、Haskellは便利です。
120 |
121 | 例えば具体的には、以下の場合にHaskellを便利に使えます。
122 |
123 | * 仕様理解
124 | * モデル確認
125 | * モデル探索
126 |
127 | 以下、それぞれについて簡単に紹介します。
128 |
129 |
130 | ## 仕様理解
131 |
132 | ハードウェアやソフトウェア開発過程などでは、例えば、自然言語と図表や式の組み合わせで表現された仕様書を理解する事が必要な局面が多くあります。
133 |
134 | 設計の上流工程で思考を広く深く及ばせておくことにより、仕様に対する思わぬ考え漏れや勘違いを防ぐことは、開発全体の質や開発速度を上げる観点で非常に有効です。
135 |
136 | Haskellは、代数的データ型やパターンマッチを簡潔に記述できる言語的な特徴を持つため、仕様を簡潔に表現することに向いています。さらに、対話環境GHCiを用いて、自分の考えを試行錯誤的に確認できます。
137 |
138 | 自然言語等の仕様を、プログラミング言語を用いて表現・写経する過程は、単純ですが、対象への理解を深める上で、意外に大きな投資対効果があります。Haskellは、このような場合に強力なツールとなります。
139 |
140 |
141 | ## モデル確認
142 |
143 | 設計の初期段階において、自分の考えミスを抽出するために、設計の中核部分を簡単なモデルで表現して確認することは、開発全体の質や開発速度を上げる観点で非常に有効です。
144 |
145 | 前節の仕様理解の場合と同様に、設計の中核モデルを簡潔に記述する目的で、Haskellを用いることが出来る場合があります。
146 |
147 | Haskellの代数的データ型とパターンマッチは、モデルの簡潔表現にもフィットする場合が多く、自分の考えを手早く確認することに有効に使用できます。
148 |
149 | さらに、Haskellで記述したモデルを、[`QuickCheck`](https://hackage.haskell.org/package/QuickCheck)ライブラリなどによるランダムテストパターンを用いて簡易検査することにより、値の範囲や特性に対する考え不足を、容赦なく効率的に抽出できます。
150 |
151 |
152 | ## モデル探索
153 |
154 | 設計の初期段階において、モデルのパラメータなどについての設計空間を、試行錯誤しながら探索したい局面があります。
155 |
156 | 前節のモデル理解の場合と同様に、設計空間を探索する目的で、Haskellを用いることが出来る場合があります。
157 |
158 | Haskellの代数的データ型とパターンマッチを用いてモデルを簡潔に記述できれば、系の大きさなどの多くのパラメータを振りながら、最適な設計値を探索することに活用できます。
159 |
160 |
161 | ## その他
162 |
163 | 思考フェーズでは、記述したプログラムの実行速度よりも、思考内容をコードで表現する速さや、試行錯誤的にコードの内容を確認・変更する速さの方が重要なことが有ります。
164 |
165 | 各々の人の思考特性によりますが、Haskellの代数的データ型とパターンマッチなどの言語的な特徴は、実行可能仕様書・実行可能思考表現として、思考を整理することに向いています。
166 |
167 | 以下のように、Haskellを用いて、簡潔に、素早く、手軽に、思考作業を支援・加速できます。
168 |
169 | * モデルなどの思考を、代数的データ型で直感的・簡潔に記述する
170 | * 処理をパターンマッチを用いて簡潔に記述する
171 | * 対話環境GHCiで、挙動と思考を手早く試行錯誤的に確認する
172 |
173 | 便利ですね。
174 |
175 |
176 | ------
177 |
178 | おわりに
179 | =======
180 |
181 | この記事では、Haskellを業務でカジュアルに使う観点やヒントについて紹介しました。
182 | 「作業」や「思考」が必要な、よりたくさんの局面でHaskellを使用できます。
183 |
184 | 関数合成、部分適用、高階関数、多相関数などの言語的な特徴は、関数をボトムアップや対話的に、素早くかつ高品質に組み上げるのに便利です。代数的データ型などの言語的な特徴は、ある種の思考パターン(選択、非一様、入れ子など)をストレートに表現するのに便利です。対話環境GHCiは、試行錯誤的に作業や思考を進めるのに便利です。
185 |
186 | Haskellに限らず、自分の思考特性にあったプログラミング言語を、業務を加速する日常的なツールとして備えておくことは有用です。
187 |
188 | しかし、そもそもプログラミング言語の可能性・適用範囲は非常に広いものです。その適用範囲を、「業務」に狭めてしまう必要もありません。
189 |
190 | プログラミング言語は、業務のみに限らず、日々の「思考」の支援・加速に広く使用できるものです。
191 |
192 |
193 | 以上、 Enjoy programming!
194 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2020/property-io.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: HspecでQuickCheckするときもshouldBeなどが使えます
3 | subHeading: quickcheck-ioパッケージのおかげ
4 | headingBackgroundImage: ../../img/background.png
5 | headingDivClass: post-heading
6 | author: Yuji Yamamoto
7 | postedBy: Yuji Yamamoto(@igrep)
8 | date: February 27, 2020
9 | tags:
10 | ...
11 | ---
12 |
13 | タイトルがほとんどすべてなんですが詳細を解説します。
14 |
15 | # 📣`shouldBe`などは`property`の中でも使えるので使ってください!
16 |
17 | みなさんはHspecでQuickCheckを使ったproperty testを書く際、どのように書いているでしょうか?
18 | 例えば[Hspecのマニュアル](https://hspec.github.io/quickcheck.html)のように、Hspecにproperty testを組み込む例として、次のような例を挙げています。
19 |
20 | ```haskell
21 | describe "read" $ do
22 | it "is inverse to show" $ property $
23 | \x -> (read . show) x == (x :: Int)
24 | ```
25 |
26 | ※[こちらのコミット](https://github.com/hspec/hspec/blob/9f3f4c38952f526701a67b6e26336a3a5aec0e89/doc/quickcheck.md)の時点での話です。
27 |
28 | `property`関数に渡した関数(以下、「`porperty`ブロック」と呼びます)の中ではHspecでおなじみの`shouldBe`などのexpectation用関数を使わず、`==`で結果を判定してますよね。
29 | このサンプルに倣って、Hspecで書いたテストにproperty testを書くときは、`==`を使ってる方が多いんじゃないでしょうか?
30 |
31 | ところが、この記事のタイトルに書いたとおり、実際のところ`property`ブロックの中でも`shouldBe`は利用できます。
32 | つまりは、こちら👇のようにも書ける、ということです!
33 |
34 | ```haskell
35 | describe "read" $ do
36 | it "is inverse to show" $ property $
37 | \x -> (read . show) x `shouldBe` (x :: Int)
38 | ```
39 |
40 | このように`property`ブロックの中でも`shouldBe`や`shouldSatisfy`といった、Hspec固有のexpectation関数を使うことの利点は、単に構文を他のテストと一貫させることができる、だけではありません。
41 | **テストが失敗したときのエラーが分かりやすくなる**、という遥かに重大なメリットがあるのです。
42 |
43 | 試しにわざとテストを失敗させてみましょう。
44 | 先ほどの例:
45 |
46 | ```haskell
47 | describe "read" $ do
48 | it "is inverse to show" $ property $
49 | \x -> (read . show) x == (x :: Int)
50 | ```
51 |
52 | における`(x :: Int)`という式を`(x + 1 :: Int)`に変えれば、必ず失敗するはずです。
53 |
54 | ```haskell
55 | describe "read" $ do
56 | it "is inverse to show" $ property $
57 | \x -> (read . show) x == (x + 1 :: Int)
58 | ```
59 |
60 | ※お手元で試す場合は[こちら](https://github.com/hspec/hspec/blob/9f3f4c38952f526701a67b6e26336a3a5aec0e89/doc/_includes/QuickCheck.hs)から元のコードを持ってきて、`stack build hspec`なりを実行した上で修正・実行するのが簡単でしょう。
61 |
62 | 結果、下記のようなエラーメッセージとなるでしょう。
63 |
64 | ```
65 | ...
66 | 1) read, when used with ints, is inverse to show
67 | Falsifiable (after 1 test):
68 | 0
69 | ```
70 |
71 | このエラーでは「テストが失敗したこと」と「どんな入力をQuickCheckが生成したか」までしか教えてくれず、わかりづらいですよね。
72 |
73 | 一方、`shouldBe`を使用して以下のように書き換えると...
74 |
75 | ```haskell
76 | describe "read" $ do
77 | it "is inverse to show" $ property $
78 | \x -> (read . show) x `shouldBe` (x + 1 :: Int)
79 | ```
80 |
81 | エラーメッセージはこう👇なります。
82 |
83 | ```
84 | 1) read, when used with ints, is inverse to show
85 | Falsifiable (after 1 test):
86 | 0
87 | expected: 1
88 | but got: 0
89 | ```
90 |
91 | 「テストが失敗したこと」と「どんな入力をQuickCheckが生成したか」に加えて、`shouldBe`に与えた両辺の式がどのような値を返したか、まで教えてくれました!
92 | 今回の例は極めて単純なのであまり役に立たないかも知れませんが、あなたが書いた関数をテストするときはやっぱり「期待される結果」と「実際の結果」両方がわかる方がデバッグしやすいですよね!
93 |
94 | と、いうわけで今後は`property`関数(あるいはその省略版の`prop`関数)に渡した関数の中でも`shouldBe`などを必ず使ってください!
95 | (せっかくなんで、今回紹介したドキュメントを[修正するためのPull request](https://github.com/hspec/hspec/pull/429)を送っておきました。これがマージされればこの記事の情報の大半は時代遅れになります)
96 |
97 | # 😕なぜ使える?
98 |
99 | しかしここで、一つ疑問が残ります。
100 | QuickCheckやHspecのドキュメントをつぶさに読んだことがある方はお気づきでしょう。
101 | QuickCheckの[`property`関数は、`Testable`という型クラスのメソッド](http://hackage.haskell.org/package/QuickCheck-2.13.2/docs/Test-QuickCheck.html#t:Testable)であるため、`Testable`のインスタンスでなければ使えないはずです。
102 | Hspecの`shouldBe`などが返す値は型シノニムのたらい回しをたどればわかるとおり、結局のところ`IO ()`型の値です。
103 | ところが`Testable`のインスタンス一覧を見る限り、`IO a`は`Testable`のインスタンスではありません。
104 | 先ほどの例のように
105 |
106 | ```haskell
107 | property $ \x -> (read . show) x `shouldBe` (x + 1 :: Int)
108 | ```
109 |
110 | と書いた場合における、関数型`(a -> prop)`のインスタンスは、`(Arbitrary a, Show a, Testable prop) => Testable (a -> prop)`という定義のとおり、関数の戻り値の型が`Testable`のインスタンスでないと、型チェックを通らないはずです。
111 | `Testable`のインスタンスでない、`IO ()`を返しているにも関わらず型エラーが起きなかったのは、一体なぜでしょうか?
112 |
113 | その秘密を探るべく、GHCiを立ち上げましょう。
114 | 先ほどの例のソースコードを`ghci`コマンドに読ませれば、まとめてHspecのモジュールも`import`できるので簡単です。
115 |
116 | ```bash
117 | > stack exec ghci .\QuickCheck.hs
118 | ```
119 |
120 | GHCiが起動したら、`:i Testable`と入力して、`Testable`型クラスのインスタンス一覧を出力しましょう。
121 |
122 | ```haskell
123 | > :i Testable
124 | class Testable prop where
125 | property :: prop -> Property
126 | {-# MINIMAL property #-}
127 | -- Defined in ‘Test.QuickCheck.Property’
128 | instance [safe] Testable Property
129 | -- Defined in ‘Test.QuickCheck.Property’
130 | instance [safe] Testable prop => Testable (Gen prop)
131 | -- Defined in ‘Test.QuickCheck.Property’
132 | instance [safe] Testable Discard
133 | -- Defined in ‘Test.QuickCheck.Property’
134 | instance [safe] Testable Bool
135 | -- Defined in ‘Test.QuickCheck.Property’
136 | instance [safe] (Arbitrary a, Show a, Testable prop) =>
137 | Testable (a -> prop)
138 | -- Defined in ‘Test.QuickCheck.Property’
139 | instance [safe] Testable ()
140 | -- Defined in ‘Test.QuickCheck.Property’
141 | instance [safe] Testable Test.HUnit.Lang.Assertion
142 | -- Defined in ‘Test.QuickCheck.IO’
143 | ```
144 |
145 | ありました!💡
146 | 最後の方にある`instance [safe] Testable Test.HUnit.Lang.Assertion`という行に注目してください。
147 | [`Test.HUnit.Lang.Assertion`](http://hackage.haskell.org/package/HUnit-1.6.0.0/docs/Test-HUnit-Lang.html#t:Assertion)は、`IO ()`の型シノニムであり、Hspecでも間接的に型シノニムとして参照されています[^hspec-expectation]。
148 | 要するに`instance [safe] Testable Test.HUnit.Lang.Assertion`という行は`instance [safe] Testable (IO ())`と読み替えることができます(`[safe]`という表記が指しているものについてはここでは省略します!すみません!)。
149 |
150 | [^hspec-expectation]: この節の冒頭で「型シノニムのたらい回し」と呼んだものを追いかけてみましょう。
151 | おなじみ[`shouldBe`](http://hackage.haskell.org/package/hspec-expectations-0.8.2/docs/Test-Hspec-Expectations.html#v:shouldBe)は[`Expectation`](http://hackage.haskell.org/package/hspec-expectations-0.8.2/docs/Test-Hspec-Expectations.html#t:Expectation)という型の値を返します。
152 | そして`Expectation`は`Assertion`の型シノニムであり、クリックすると[`Test.HUnit.Lang.Assertion`](http://hackage.haskell.org/package/HUnit-1.6.0.0/docs/Test-HUnit-Lang.html#t:Assertion)であることがわかります。
153 | そして`Assertion`はそう、`type Assertion = IO ()`とあるとおり`IO ()`なのです。やっと知ってる型にたどり着きました😌。
154 |
155 | 紹介したとおり`Testable`のドキュメントには`Testable Assertion`なんて記載はありませんし、じゃあ一体どこで定義したのか、というとそう、続く行に`-- Defined in ‘Test.QuickCheck.IO’`と書かれているとおり、[`Test.QuickCheck.IO`](https://hackage.haskell.org/package/quickcheck-io-0.2.0/docs/Test-QuickCheck-IO.html)というモジュールで定義されています!
156 |
157 | `Test.QuickCheck.IO`は、名前のとおりQuickCheckの`Testable`について、`IO`のorphan instanceを定義するためのモジュールです。
158 | これを[`import`している](https://github.com/hspec/hspec/blob/226510631f24b674827e99d17d10f9f92440c5a9/hspec-core/src/Test/Hspec/Core/QuickCheckUtil.hs#L18)が故に、Hspecでは`property`ブロックの中で`shouldBe`などが利用できるんですね!
159 |
160 | 結論:
161 |
162 | - orphan instanceわかりづらい😥
163 | - GHCiの`:i`はorphan instanceであろうとインスタンスを定義した箇所を見つけてくれるから便利!
164 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2021/haskell-day-2021.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskell Day 2021を開催します
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | author: Haskell-jp
6 | postedBy: Kazuki Okamoto (@kakkun61)
7 | date: June 14, 2021
8 | tags: イベント
9 | ---
10 |
11 | [Haskell Day 2021](https://haskell.jp/haskell-day-2021/)を開催します!
12 |
13 | [](https://haskell.jp/haskell-day-2021/)
14 |
15 | こんにちはkakkun61こと岡本和樹です。
16 |
17 | この記事では[Haskell Day 2021](https://haskell.jp/haskell-day-2021/)の紹介と開催の経緯などを記載します。
18 |
19 | # 経緯
20 |
21 | Haskell Dayは日本語で開催されるHaskellに関するイベントとしては最多の参加者を誇るイベントです。これまで2012・2016・2018・2019と開催してきました。新型コロナウイルスの影響により、残念ながら2020は開催しませんでしたが、2021は*オンライン*イベントとして開催します。
22 |
23 | このようなオンラインイベントの開催は未経験だったため、さまざまなイベント形式を検討した結果、今回は事前録画動画の予約公開という形式を採用しました。生放送ももちろん検討しましたが、ノウハウ不足の中で一発勝負という生放送はリスクが大きいという判断をしました。録画公開における臨場感の不足をおぎなうことを期待し、YouTubeの[プレミア公開](https://creatoracademy.youtube.com/page/course/hype-with-premieres)を使用しリアルタイムチャットによる発表者と視聴者・視聴者同士の交流をできるように予定しています。
24 |
25 | # 発表者募集
26 |
27 | 現在[発表者募集](https://haskell.jp/haskell-day-2021/#call-for-papers)中です!
28 |
29 | 今回はオンライン開催ということで、お手数ですが発表者にもオンサイトのイベントと異なった準備をお願いすることになります。運営としてできるかぎりのサポートをしますので安心して応募いただければと思います。
30 |
31 | # 参加登録
32 |
33 | [Connpass](https://haskell-jp.connpass.com/event/215363/)にて参加登録の受け付けもしていますので視聴者の方も登録をお願いします。
34 |
35 | その他のくわしい情報は[Haskell Day 2021イベントページ](https://haskell.jp/haskell-day-2021/)をご覧ください。
36 |
37 | みなさまのご応募をお待ちしています。またお体にお気をつけください。
38 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2021/symbols-in-ghc.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskellにおける記号の調べ方
3 | headingBackgroundImage: ../../img/background.png
4 | headingDivClass: post-heading
5 | author: YAMAMOTO Yuji
6 | postedBy: YAMAMOTO Yuji(@igrep)
7 | date: December 25, 2021
8 | ---
9 |
10 | この記事は[ググって解決しづらかったこと Advent Calendar 2021](https://qiita.com/advent-calendar/2021/gseach)の25日目の記事です。[Haskell-jp WikiのHaskellの歩き方](https://wiki.haskell.jp/Hikers Guide to Haskell)というページにもほぼ同じことを書きましたが、今回はよい機会なので実例を加えつつ詳しく紹介させてください。
11 |
12 | # 二項演算子(記号関数)の調べ方
13 |
14 | よく知られているとおり、Haskellには二項演算子をプログラマーがかなり自由に定義できるという、とても変わった特徴があります。他のプログラミング言語でも使う標準的なもの(例: `+`, `*`, `&&`など)を名前空間を絞って置き換えるほか、[例えばかのlensパッケージのように](https://hackage.haskell.org/package/lens-5.1/docs/Control-Lens-Operators.html)、ライブラリーの作者があたかも新しい構文を作り上げるかのごとく独自の二項演算子を提供することができます。
15 |
16 | これは面白い機能ではあるものの、しばしば混乱を招く機能でもあります。後述するその他の記号との区別がつきにくいですし、一般的な検索エンジンで検索することさえままなりません。[Googleはプログラミングでよく使われる記号による検索をサポートはしている](https://blog.fkoji.com/2017/03052055.html)ものの、Haskellでしか見ないような記号の組み合わせは到底無理でしょう。
17 |
18 | そんな背景もあり、Haskellを使う人はしばしば[Hoogle](https://hoogle.haskell.org/)などの、関数名で検索できる検索エンジンを使用することになります。こちらは二項演算子の名前での検索もサポートしています。
19 |
20 | 例えばlensパッケージでおなじみの`^.`で検索すると[次のような結果になりました](https://hoogle.haskell.org/?hoogle=%5E.):
21 |
22 | 
23 |
24 | lensパッケージ以外でも、同様の`^.`が定義されているのが分かりますね。lensパッケージは依存関係がとても大きい一方、`^.`などの定義は十分単純でコピペしてもいいくらい小さいので、このようにいくつものパッケージで定義されています。
25 |
26 | また、特によく使われる二項演算子はFPCompleteのウェブサイトでもまとめられています:
27 |
28 | [Operator Glossary](https://www.fpcomplete.com/haskell/tutorial/operators/)
29 |
30 | # ユーザーが定義した二項演算子ではないものの調べ方
31 |
32 | Haskell、というかそのデファクトスタンダードな処理系であるGHCでは、[言語拡張](https://haskell.jp/blog/posts/2018/about-ghc-exts-1.html)という形で長年新しい構文が提案されています[^ghc-proposals]。その中には、当然これまでにない方法で記号を使っているものもあります。そうした記号はプログラマーが定義した関数ではないので、前述のHoogleなどを使った方法が通用しません。そこで、当ブログにも何度も寄稿いただいた\@takenobu\_hsさんが、言語拡張によるものも含めた、Haskellの構文における記号の一覧を作ってくださいました!
33 |
34 | [takenobu-hs/haskell-symbol-search-cheatsheet](https://github.com/takenobu-hs/haskell-symbol-search-cheatsheet)
35 |
36 | [^ghc-proposals]: 余談: [ghc-proposals](https://github.com/ghc-proposals/ghc-proposals)に送られたPull requestを見ると、今どのような提案が議論されているか分かります。
37 |
38 | 実は日本語版も[Qiitaに](https://qiita.com/takenobu-hs/items/b95f0a4409c59440d4a9)あるのですが、上記のGitHub版の方が更新されているようです。そこで、今回はおまけとして、[GitHub版の方にも載っている](https://github.com/takenobu-hs/haskell-symbol-search-cheatsheet#--overloadedrecorddot)、GHCに最近(バージョン9.2.1以降に)追加された、新しいピリオド `.` の使い方を紹介しましょう。
39 |
40 | 従来、Haskellでピリオドといえば関数合成を表す二項演算子でした:
41 |
42 | ```haskell
43 | ghci> f x = x + 1
44 | ghci> g x = x * 3
45 | ghci> h = g . f
46 | ghci> h 2
47 | 9 -- 2 に + 1 して * 3 した結果
48 | ```
49 |
50 | 数学における関数合成の記号「g ∘ f」に似せてピリオドを採用したのでしょう。しかし、世は今まさに**大「ピリオドといえばフィールド[^field]へのアクセス演算子じゃろがい」時代**です。それでなくてもHaskellのレコード型は扱いにくいと言われているのに、フィールドへのアクセスまで変なやり方でした[^prefer]:
51 |
52 | ```haskell
53 | data SomeRecord =
54 | SomeRecord { field1 :: String, field2 :: Int }
55 |
56 | someRecord = SomeRecord "value1" 2
57 |
58 | ghci> field1 someRecord
59 | "value1"
60 |
61 | ghci> field2 someRecord
62 | 2
63 | ```
64 |
65 | [^field]: 他のプログラミング言語では「プロパティー」と呼ばれることも多いですが、ここではHaskellのレコード型における用語に合わせました。
66 |
67 | [^prefer]: 個人的にはゲッターが関数になるのはとても直感的な気がして割と好きでしたが、確かにデメリットもとても多い仕様でした。セッターは単純な関数になってないですしね。
68 |
69 | そこで、GHC 9.2からは[`OverloadedRecordDot`](https://downloads.haskell.org/ghc/9.2.1/docs/html/users_guide/exts/overloaded_record_dot.html#overloaded-record-dot)という言語拡張が導入され、これを有効にしたファイルではおなじみの言語のようにピリオドでレコードのフィールドにアクセスできるようになりました:
70 |
71 | (以下はGHCiで使用した例です)
72 |
73 | ```haskell
74 | ghci> :set -XOverloadedRecordDot
75 |
76 | ghci> someRecord.field1
77 | "value1"
78 |
79 | ghci> someRecord.field2
80 | 2
81 |
82 | -- ⚠️ピリオドの前後に空白を入れると関数合成として解釈されてしまう!
83 | ghci> someRecord . field2
84 |
85 | :5:1: error:
86 | ? Couldn't match expected type ‘Int -> c’
87 | with actual type ‘SomeRecord’
88 | ? In the first argument of ‘(.)’, namely ‘someRecord’
89 | In the expression: someRecord . field2
90 | In an equation for ‘it’: it = someRecord . field2
91 | ? Relevant bindings include
92 | it :: SomeRecord -> c (bound at :5:1)
93 | ```
94 |
95 | `OverloadedRecordDot`についてのより詳しい解説は、[Haskell Day 2021における、fumievalさんの発表](https://youtu.be/haZl-q6mfyk?t=2581)をご覧ください。
96 |
97 | # まとめ
98 |
99 | - 他のプログラマーが定義した、二項演算子(記号関数)を調べるときは:
100 | - [Hoogle](https://hoogle.haskell.org/)
101 | - 補足: Stackageの最新のLTSから検索したいときは[Stackage](https://www.stackage.org/)のページ上部にあるフォームで検索してみましょう。こちらも内部はHoogleが使われています。
102 | - それ以外の場合は:
103 | - [takenobu-hs/haskell-symbol-search-cheatsheet](https://github.com/takenobu-hs/haskell-symbol-search-cheatsheet)
104 | - Haskellのレコード型に嫌気が差したら:
105 | - [Haskell Day 2021における、fumievalさんの発表](https://youtu.be/haZl-q6mfyk?t=2581)を観て[`OverloadedRecordDot`拡張](https://downloads.haskell.org/ghc/9.2.1/docs/html/users_guide/exts/overloaded_record_dot.html#overloaded-record-dot)について勉強しましょう。
106 |
107 | 🎁それでは2022年もHappy Haskell Hacking!!🎅
108 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/2022/disband_admins.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 一般社団法人としてのHaskell-jp Admins解散のお知らせ
3 | headingBackgroundImage: ../img/background.png
4 | headingDivClass: post-heading
5 | author: Haskell-jp Admins
6 | date: September 18, 2022
7 | tags: Haskell-jp Admins
8 | ...
9 | ---
10 |
11 | 誠に残念ながら、一般社団法人としての日本Haskellユーザーグループ管理委員会(通称Haskell-jp Admins)は、去る2022年4月16日を以て解散しました。先日、解散後に必要な処理のほぼすべてが完了しましたので、遅くなってしまいましたが、改めてこちらで報告致します。
12 |
13 | # 背景
14 |
15 | 解散の背景を一言で申しますと、「お金がかかりすぎる上に、士気も下がってしまったから」です。設立前に調査した際、法人住民税のルールを誤解してしまったことで想定より費用がかさんだことや、当初活動の一環として掲げていた大規模なオフラインイベントが、現状のコロナ禍において難しく、その上、代表を含む社員自身の開催するモチベーションが下がってしまっていることを鑑みて、先般行われた第1期の社員総会で解散する事を合意しました。
16 |
17 | # 今後の活動
18 |
19 | 「一般社団法人」という法人格を失ってしまったので、法律上必要な場面において「日本Haskellユーザーグループ管理委員会」という名前を使用することはできなくなってしまいました。それでもできる範囲内で、任意団体として今までどおりの活動を継続したいと思います。
20 |
21 | 具体的には、
22 |
23 | - プログラミング言語Haskellに関するイベントの企画・開催・運営
24 | - 任意団体として適宜実施します
25 | - haskell.jp ドメインの維持・管理
26 | - ひとまず、代表であった山本悠滋が個人として引き継ぐことにします
27 | - [Haskell-jpのSlack Workspace](https://haskell.jp/signin-slack.html)を始めとする、交流や情報共有を行う場の提供・管理・運営
28 | - こちらは引き続き行います
29 |
30 | # 今後の連絡先
31 |
32 | こちらは[設立時の記事](../about_admins.html)から特に変更はありません。[該当するセクション](../about_admins.html#今後の活動と連絡先)をご覧ください。
33 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/about_admins.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 日本Haskellユーザーグループ管理委員会(Haskell-jp Admins)設立のお知らせ
3 | headingBackgroundImage: ../img/background.png
4 | headingDivClass: post-heading
5 | author: Haskell-jp Admins
6 | date: March 29, 2021
7 | tags: Haskell-jp Admins
8 | ...
9 | ---
10 |
11 | # 2022/09/18 重大な追記
12 |
13 | ⚠️一般社団法人としての日本Haskellユーザーグループ管理委員会は、2022年4月16日を以て解散しました。今後は任意団体として活動を続けます。詳細は[一般社団法人日本Haskellユーザーグループ管理委員会 解散のお知らせ](./2022/disband_admins.html)をご覧ください。
14 |
15 | 以下では、記録のために設立当時の記事をほぼそのまま残しています。
16 |
17 | -----------------
18 |
19 | 去る2021年2月9日、任意団体であり明確な会員資格を持たない、[日本Haskellユーザーグループ(Haskell-jp)](https://haskell.jp/blog/posts/about_us.html)における共有財産やコミュニケーションの場の管理・運営を担う法人として、一般社団法人日本Haskellユーザーグループ管理委員会(通称 Haskell-jp Admins。[法人番号 5020005014971](https://www.houjin-bangou.nta.go.jp/henkorireki-johoto.html?selHouzinNo=5020005014971))を設立しました。法人格を持つことを活かして、Haskell-jp Adminsは次の事業に取り組みます。
20 |
21 | - プログラミング言語Haskellに関するイベントの企画・開催・運営
22 | - イベントの会場を借りたり、ノベルティーを作成したりする際の名義として使用する予定です
23 | - haskell.jp ドメインの維持・管理
24 | - [Haskell-jpのSlack Workspace](https://haskell.jp/signin-slack.html)を始めとする、交流や情報共有を行う場の提供・管理・運営
25 | - そのほか、上記に関連して必要なこと
26 |
27 | # 背景
28 |
29 | そもそもの設立の動機は、山下さん([\@nobsun](https://twitter.com/nobsun))の好意によって個人名義で保有していたhaskell.jp ドメインを共同で管理出来るようにするためでした。ドメインを団体として保有するには、法人格と、法人名義の銀行口座が必要なのです。これ以外にも、Haskell-jpとして共有する価値のあるアカウントを管理する際の名義として、随時「日本Haskellユーザーグループ管理委員会」を使用します。
30 |
31 | # 今後の活動と連絡先
32 |
33 | Haskell-jp Adminsが出来たからといって、Haskell-jpのあり方が大きく変わることはありません。今後もSlackで質問したり議論したり[ブログ](https://haskell.jp/blog/)記事を書いたりしましょうというドメインを活かし、「公式面して」自由に活動する方をいつでも待っています!
34 |
35 | - 公の場で提案・相談したい場合は:
36 | - 前述の[Haskell-jpのSlack Workspace](https://haskell.jp/signin-slack.html)の#randomチャンネルなどで投稿いただくか、
37 | - [haskell-jp/communityにissue](https://github.com/haskell-jp/community/issues)として登録したり、
38 | - [Haskell-jpのTwitterアカウント \@haskell\_jp](https://twitter.com/haskell_jp)にメンションをください。
39 | - プライベートに提案・相談したい場合は:
40 | - haskell-jp-admins@googlegroups.com にメールを送ってください
41 |
42 | 我々Haskell-jp Adminsは、そうした活動をバックアップするために種々の問題に取り組んでいきます。
43 |
44 | # 現在の理事・社員
45 |
46 | - 代表理事: 山本悠滋([\@igrep](https://twitter.com/igrep))
47 | - 社員:
48 | - 中嶋大嗣([\@nakaji\_dayo](https://twitter.com/nakaji_dayo/))
49 | - 山下伸夫([\@nobsun](https://twitter.com/nobsun))
50 | - 岡本和樹([\@kakkun61](https://twitter.com/kakkun61))
51 | - 木下郁章([\@fumieval](https://twitter.com/fumieval))
52 | - 廣瀬達也([\@lotz84\_](https://twitter.com/lotz84_))
53 |
54 | # 所在地
55 |
56 | **2022/09/18 編集**: 法人格を廃止するとともに、契約したバーチャルオフィスの規約に従い、こちらに記載していた住所も削除しました。
57 |
58 | # 定款
59 |
60 | こちらに一部個人情報を削除した上で掲載しています。
61 |
62 | [一般社団法人 日本Haskellユーザーグループ管理委員会 定款](https://github.com/haskell-jp/community/blob/master/admins/article.md)
63 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/about_us.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Haskellと日本Haskellユーザーグループについて
3 | headingBackgroundImage: ../img/background.png
4 | headingDivClass: post-heading
5 | heading: Haskellと日本Haskellユーザーグループについて
6 | author: Haskell-jp
7 | date: April 30, 2017
8 | tags: Haskell-jp
9 | ...
10 | ---
11 |
12 | # Haskellについて
13 |
14 | Haskellは、関数型プログラミングの**強力な**サポートと、厳密かつ柔軟な静的型付けを特徴としたプログラミング言語です。
15 | そうした特徴によってHaskellは、バグが少なく、堅牢でメンテナビリティーの高いソフトウェア作りをサポートします。
16 |
17 | 加えて、下記のような際立った機能を備えています。
18 |
19 | - 型によってプログラムの副作用を管理できる仕組み (再代入不可能な変数、`IO`をはじめとする状態系モナド)
20 | - モナドの言語仕様レベルでのサポート (`do`記法)
21 | - 型推論や型クラスといった、型の厳密さとプログラムの書きやすさを両立させる仕組み
22 | - デフォルトでの非正格評価
23 | - 中置演算子の自由な定義
24 |
25 |
29 |
30 | # Haskell-jpこと日本Haskellユーザーグループについて
31 |
32 |
33 |
34 | 日本Haskellユーザーグループは、日本におけるプログラミング言語Haskellの普及活動と、Haskellを利用する人々のサポートを行うグループです。
35 | 日本における代表的なHaskellユーザーグループとなることを目指します。
36 | 「日本Haskellユーザーグループ」ではやや長いので、「Haskell-jp」という愛称を設定しました。
37 |
38 | 現在は主に次のような活動を行っています。
39 |
40 | - Haskellの利用を支援する情報や、Haskellに関するニュースの日本語への翻訳。
41 | - 日本語でのHaskellについての情報発信。
42 | - [Haskell レシピ集](https://github.com/haskell-jp/recipe-collection)
43 | - [Haskell-jp Blog](https://haskell.jp/blog)
44 | - [Haskell-jp Wiki](https://wiki.haskell.jp)
45 | - [公式Slackチーム](https://haskell-jp.slack.com)を通じたHaskellユーザーのサポート・コミュニティ拡大の支援。
46 | - 発言は[こちらのリポジトリー](https://github.com/haskell-jp/slack-log)の[doc/jsonディレクトリー](https://github.com/haskell-jp/slack-log/tree/master/doc/json)に**保存・公開**されます。あらかじめご容赦ください。
47 | - [定期的な勉強会やイベント](https://haskell-jp.connpass.com)の開催を通じた、ユーザー同士の交流の活性化。
48 | - Haskell-jp もくもく会: 趣味や仕事で書いてるプログラムの続きを書く、最近気になるあのライブラリを使ってみる、0から勉強してみる、など、Haskellに関する作業をもくもくとやったり、希望者でLTを行ったりするゆるい会です。[Haskellもくもく会](https://haskellmokumoku.connpass.com)を前身としています。
49 |
50 | # Haskell-jp Adminsこと日本Haskellユーザーグループ管理委員会について
51 |
52 | Haskell-jp Adminsについては[こちらの設立のお知らせ](about_admins.html)をご覧ください。
53 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/grc.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 「相互を尊重したコミュニケーションのためのガイドライン」制定のお知らせ
3 | headingBackgroundImage: ../img/background.png
4 | headingDivClass: post-heading
5 | author: Haskell-jp Admins
6 | date: May 30, 2021
7 | ...
8 | ---
9 |
10 | [先日のHaskell-jp Admins](about_admins.html)と同様に事務的な連絡で恐縮ですが、当ブログや[Haskell-jpのSlack Workspace](https://haskell.jp/signin-slack.html)、[GitHubのOrganization](https://github.com/haskell-jp)などにおけるコミュニケーションに適用される、[「相互を尊重したコミュニケーションのためのガイドライン」](https://github.com/haskell-jp/community/blob/master/GRC.md)を制定致しました。
11 |
12 | [Haskell-jp 相互を尊重したコミュニケーションのためのガイドライン](https://github.com/haskell-jp/community/blob/master/GRC.md)
13 |
14 | こちらは[Haskell FoundationにおけるGuidelines for Respectful Communication (GRC)](https://haskell.foundation/guidelines-for-respectful-communication/)を日本語に翻訳し、運用主体などをHaskell-jpにおける実態に合わせて書き換えたものです。いわゆる「行動規範(Code Of Conduct。しばしば「COC」と略されます)」と同じ役割を果たすものですが、行動規範と異なり、禁止事項よりも推奨事項を数多く挙げているのが特徴です。[このGRCを翻訳する前に、COCを提案した際の議論](https://github.com/haskell-jp/community/pull/29)においてGRCのこうした特徴が好まれ、採用に至りました。
15 |
16 | このGRCは、今後[Haskell-jpのSlack Workspace](https://haskell.jp/signin-slack.html)や[Haskell-jpのGitHubにおけるOrganizationが管理するリポジトリー](https://github.com/haskell-jp/)、それからHaskell-jpとして開催するイベントなど、様々な場面で適用されます。参加されるみなさんはご理解の上、快適なコミュニティー活動をお楽しみください。
17 |
18 | 加えて、もちろん今秋開催予定の[Haskell Day 2021](https://haskell.jp/haskell-day-2021/)においても、こちらのGRCを採用します。参加者、発表者、運営者の方々はご理解とご協力をよろしくお願いします。
19 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/links.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 相互リンク集
3 | headingBackgroundImage: ../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: Haskell-jpが応援するWebサイト一覧
6 | author: Haskell-jp
7 | date: May 18, 2017
8 | ...
9 | ---
10 |
11 | [このほかに、Haskell-jp Wikiにもリンク集があります!](https://wiki.haskell.jp/Links)
12 |
13 | # Haskell-jpが応援するWebサイト一覧
14 |
15 | この一覧への[登録方法は下記](#howToGetSupport)をご覧ください。
16 |
17 |
32 |
33 | # この一覧への登録方法 {#howToGetSupport}
34 |
35 | 登録条件: 広い意味でプログラミング言語Haskellに関連したことが書いてあるWebサイトであること。
36 |
37 | 1. [こちらのリポジトリーでIssueを作成](https://github.com/haskell-jp/blog/issues/new?title=相互リンク作成依頼:(あなたのWebサイトの名前)&body=(一行目にあなたのWebサイトのURLを書いてください。)%0D%0A%0D%0A運営者の氏名(ハンドルネーム可): (必須ではありません)%0D%0A%0D%0A(何かあればここに一言コメントをこちらに。))してください。
38 | 1. 担当者が承認すると同時に、必要なHTMLのスニペットを提示するので、それをあなたのサイトに張り付けてください!
39 | - バナーの画像はSVGなので、大きさは適当にいじっていただいてかまいません!ただ、あまりにも小さくしたり、アスペクト比を変えるのはやめていただきたいですが...。
40 | 1. 以上!
41 |
42 | ## 承認する担当者へ
43 |
44 | TODO: 承認を自動化するツールを作る。
45 |
46 | 1. 対象のWebサイトを承認する場合は、承認する旨を伝えるとともに、下記のスニペットをコピペして、`(siteId)`と書かれた箇所を「追加するWebサイトのURLからスキーム(`http://`や`https://`の部分)を取り除いたもの」で置き換え、対象のWebサイトに貼り付けてもらうようIssueのコメントで依頼しましょう。
47 | ```html
48 | ```html
49 |
50 | ```
51 | ```
52 | 1. 続いて、下記のmarkdownのスニペットにおける`(siteId)`の部分を、先ほどの「追加するWebサイトのURLからスキームを取り除いたもの」で置き換え、[このページを編集](https://github.com/haskell-jp/blog/edit/master/preprocessed-site/posts/links.md)し、追加しましょう。
53 |
54 | ```html
55 | (追加するWebサイトの名前)( by 運営者の氏名があれば)
56 | ```
57 |
--------------------------------------------------------------------------------
/preprocessed-site/posts/template.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 記事のタイトル
3 | headingBackgroundImage: ../img/background.png
4 | headingDivClass: post-heading
5 | subHeading: (副題が必要な場合はこちらを)
6 | author: (あなたの名前。HTMLのmetaタグの`author`や、フッターにおけるコピーライトマークの箇所に使用されます)
7 | postedBy: (記事一覧や見出しに載る、あなたの名前。authorと異なり、このようにHTMLタグを含めることもできます。省略した場合、`author`の内容が使用されます)
8 | date: April 29, 2017 # 公開日。仮でよいので埋めてください。
9 | draft: true # この行は原則として削除してください。
10 | ...
11 | ---
12 |
13 | Haskell-jpなので基本的に日本語の記事を公開しましょう。
14 |
15 | ## マークダウンを使えます
16 |
17 | [Pandocのマークダウン](http://sky-y.github.io/site-pandoc-jp/users-guide/#pandocs-markdown)を使えるので、脚注なども[^1]このようにいれられます。
18 |
19 | ## 脚注
20 |
21 | [^1]: ただの脚注です。
22 | テスト以外の何物でもありません。
23 |
--------------------------------------------------------------------------------
/preprocessed-site/templates/post-list.html:
--------------------------------------------------------------------------------
1 | $for(posts)$
2 | $if(draft)$
3 | $else$
4 | $if(language)$
5 |
6 | $else$
7 |
8 | $endif$
9 |
10 |
11 | $title$
12 |
13 | $if(subHeading)$
14 |
15 | $subHeading$
16 |
17 | $endif$
18 |
19 | $if(postedBy)$
20 |
Posted by $postedBy$ on $date$
21 | $else$
22 |
Posted by $author$ on $date$
23 | $endif$
24 |
25 |
27 |
28 | $endif$
29 | $endfor$
30 |
--------------------------------------------------------------------------------
/preprocessed-site/templates/post.html:
--------------------------------------------------------------------------------
1 | $if(language)$
2 |
3 | $else$
4 |
5 | $endif$
6 |
7 |
28 |
29 |
30 | $body$
31 |
32 |
33 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/stack.yaml:
--------------------------------------------------------------------------------
1 | flags: {}
2 | packages:
3 | - '.'
4 | extra-deps:
5 | []
6 | resolver: lts-19.22
7 |
--------------------------------------------------------------------------------
/stack.yaml.lock:
--------------------------------------------------------------------------------
1 | # This file was autogenerated by Stack.
2 | # You should not edit this file by hand.
3 | # For more information, please see the documentation at:
4 | # https://docs.haskellstack.org/en/stable/lock_files
5 |
6 | packages: []
7 | snapshots:
8 | - completed:
9 | size: 619399
10 | url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/22.yaml
11 | sha256: 5098594e71bdefe0c13e9e6236f12e3414ef91a2b89b029fd30e8fc8087f3a07
12 | original: lts-19.22
13 |
--------------------------------------------------------------------------------
/test/DocTest.hs:
--------------------------------------------------------------------------------
1 |
2 | module Main (main) where
3 |
4 | import Prelude
5 |
6 | import Data.Monoid ((<>))
7 | import System.FilePath.Glob (glob)
8 | import Test.DocTest (doctest)
9 |
10 | main :: IO ()
11 | main = glob "src/**/*.hs" >>= doDocTest
12 |
13 | doDocTest :: [String] -> IO ()
14 | doDocTest options = doctest $ options <> ghcExtensions
15 |
16 | ghcExtensions :: [String]
17 | ghcExtensions =
18 | [
19 | -- "-XConstraintKinds"
20 | -- , "-XDataKinds"
21 | -- ,"-XDeriveDataTypeable"
22 | -- , "-XDeriveGeneric"
23 | -- , "-XEmptyDataDecls"
24 | -- , "-XFlexibleContexts"
25 | -- , "-XFlexibleInstances"
26 | -- , "-XGADTs"
27 | -- , "-XGeneralizedNewtypeDeriving"
28 | -- , "-XInstanceSigs"
29 | -- , "-XMultiParamTypeClasses"
30 | -- , "-XNoImplicitPrelude"
31 | -- , "-XOverloadedStrings"
32 | -- , "-XPolyKinds"
33 | -- , "-XRankNTypes"
34 | -- , "-XRecordWildCards"
35 | -- , "-XScopedTypeVariables"
36 | -- , "-XStandaloneDeriving"
37 | -- , "-XTupleSections"
38 | -- , "-XTypeFamilies"
39 | -- , "-XTypeOperators"
40 | ]
41 |
--------------------------------------------------------------------------------