clock2023-12-18

VimConf2023で登壇してきました!

VimConf参加記事をブログに書くまでがVimConf!! VimConf参加記事をブログに書くまでがVimConf!!

VimConf2023何をしてきたか

VimConf2023で、30分の登壇をしてきました。

タイトルは「Boost your vimrc with some template techniques!」で、 .vimrcを書くときに便利なVim script…

clock2023-11-30

技術書典15で数学入門書の続編(せつラボ2)を頒布してきました!

技術書典15について


本稿は 🎉HIKKYアドベントカレンダー 5日目🎉 の記事です!

えっ、HIKKYと関係なくない? と思ったそこのあなた。
その通りです!

ともかくここは、HIKKYの一員の活動として紹介させていただきます。
HIKKYは懐が広いぜ!


頒布した本

clock2023-11-12

正誤表 - せつラボ ~雲と天使と関手圏~

内容

せつラボ ~雲と天使と関手圏~の誤りについての、Web正誤表です。 逐次、更新されます。

誤りと修正

発生した日もしくは版 修正した日もしくは版
まだなし
clock2023-11-07

【会場限定25%オフ】技術書典15にて、圏論入門小説2巻目を頒布します!【う14】

概要

技術書典15にて、新刊、圏論入門小説「せつラボ」シリーズ2巻目を頒布します!

  • タイトル: せつラボ2~雲と天使と関手圏~
  • ページ数: 100p
  • 価格: 1,000円 ※

※ただし会場限定で、1&2巻セットが1,500円になります!

会場限定で、1&2巻セットを25%オフ1,500円で予定しています!
ぜひお越しください!

技術書典ページ

clock2022-11-01

Nuxt3とMSWで「The script has an unsupported MIME type ('text/html')」が出た

間違い

間違いは$ msw init src/static --savesrc/static)していたことだった。 Nuxt2のプロジェクトのひとつではsrc/staticで成功していたので、油断していた。

The script has an unsupported MIME type ('text/html').

今回のプロジェクトではSPAを採用しているので、MSWで定義した/mock/fooエンドポイントで404のhtmlが取れてしまって、text/htmlと言われていた。

修正

公式ドキュメントの'Where is my "public" directory?'に書いてある通り、Vue.jsでは./publicmockServiceWorker.jsを配置する。

今回のプロジェクトではpublicディレクトリが、都合上./src

clock2022-01-29

ComboGestureExpressions_V1.5.2のEE Property Explorerで表情が生成されない

EE Property Explorer

これ↓

right

問題: EE Property Explorerで表情が生成されない

こうなってしまった
プレビューが生成されておらず、灰色の顔画像ばっかり

left

UnityのConsoleにはAnimationEvent has no function name specified!というエラーが大量に出ていた 関係なかった

修正

clock2021-07-23

UdonSharpでメソッドをthis.SendCustomNetworkEvent()で呼び出すときは、メソッドをprivateにしない

❌ 「howdy :)」が表示されない

public void Start() {
  this.SendCustomNetworkEvent(NetworkEventTarget.All, "Foo");
}

private void Foo() {
  Debug.LogError("howdy :)");
}

⭕ 「howdy :)」が表示される

public void Start() {
  this.SendCustomNetworkEvent(NetworkEventTarget.All, "Foo");
}

// Not `private`
public void Foo() {
  Debug.LogError("howdy :)");
}

当たり前だけど!!!

すごいいやだった!!

clock2021-07-02

VivaldiでTwitterのシェアボタンが表示されなくなってた

Boothで商品を購入したので、Twitterにシェアしたいけど、ボタンがない

あれ?

invisible

そういえばVivaldiに、ビルトインの広告ブロッカーが最近搭載されてた気がする

newer prefs

オフにしてみる

unblocking

表示された!✨

visible

clock2021-04-26

アバターの削除してしまった服や服飾を、もう一度アバターに追加する

概要

ミーシェちゃんの下着をHierarchy消しちゃったけど、やっぱり使いたい!

1

問題

「元prefabあるんだし、そっちからコピーしてくればいいんじゃ?」 と思い、下記手順を実行しましたが

  1. ミーシェちゃんのprefabから、HierarchyにMishe (GameObject) を追加
  2. Mishe/Mishe_underwearをMishenka word-mishenka の配下にコピー

2

HierarchyからMisheを削除すると、ずれおちちゃいます。 Mishenka/Mishe_underwear(元Mishe/Mishe_underwear

clock2021-02-07

【Nuxt.js】storeでないモジュールを`@/store/`配下に置いてはいけない

【Nuxt.js】storeでないモジュールを@/store/配下に置いてはいけない。notice-at

問題と解決

ある日、Nuxt.jsのstore機構を理解しないまま./store/password.tsというファイルを作成すると、下記の実行時エラーになった。

client.js?06a0:97 TypeError: Cannot set property password of #<Object> which has only a getter
    at eval (index.es.js?9e80:61)
    at Array.forEach (<anonymous>)
    at useAccessor (index.es.js?9e80:59)
    at eval (index.es.js?9e80:66)
    at _callee$ (nuxt-typed-vuex.js?679e:8)
    at tryCatch (runtime.js?96cf:62)
    at Generator.invoke [as _invoke] (runtime.js?96cf:296)
    at Generator.prototype.<computed> [as next] (runtime.js?96cf:114)
    at asyncGeneratorStep (asyncToGenerator.js?1da1:3)
    at _next (asyncToGenerator.js?1da1:25)

./store/password.tsを削除すると、この実行時エラーは出なくなる。

原因

Nuxt.jsのプロジェクトで@/store/配下にモジュールを作ると、それはストアになる。

通常のモジュールは、@/store

clock2021-01-09

Google Cloud Functionsでnode.jsを使う場合、devDependenciesを使うとデプロイが失敗する

Google Cloud Functionsのプロジェクトではnpm install --save-devyarn add --devは使わずに、npm installyarn addを使うこと。

もししてしまっても、package.jsondevDependenciesを手動でdependenciesに移せば大丈夫。

問題

これになる 👇

$ yarn deploy
yarn run v1.22.5
$ firebase deploy --only functions

=== Deploying to 'foo'...

i  deploying functions
Running command: yarn build
$ tsc

...

✔  functions: . folder uploaded successfully
i  functions: updating Node.js 12 function bar(us-central1)...
⚠  functions[bar(us-central1)]: Deployment error.
Function failed on loading user code. This is likely due to a bug in the user code.
Error message: Error: please examine your function logs to see the error cause: https://cloud.google.com/functions/docs/monitoring/logging#viewing_logs.
Additional troubleshooting documentation can be found at https://cloud.google.com/functions/docs/troubleshooting#logging.
Please visit https://cloud.google.com/functions/docs/troubleshooting for in-depth troubleshooting documentation.

...

package.jsonの一部

  "devDependencies": {
    "request-promise-native": "^1.0.9"
  },

解決

長らく悩んで GCPのログエクスプローラーを見てみると、ちゃんと書いてあった……。

{
  "textPayload": "Did you list all required modules in the package.json dependencies?",
  "insertId": "000000-ad829364-20bb-4471-96d7-51b483614caf",
  "resource": {
    "type": "cloud_function",
    "labels": {
      "project_id": "foo",
      "function_name": "bar",
      "region": "us-central1"
    }
  },
  "timestamp": "2021-01-09T13:54:40.865Z",
  "labels": {
    "execution_id": ""
  },
  "logName": "projects/foo/logs/cloudfunctions.googleapis.com%2Fcloud-functions",
  "receiveTimestamp": "2021-01-09T13:54:42.400107672Z"
}

ぴえんでございます!!!!!

clock2020-12-30

アバター改変で服などを着せるするなら、絶対にボーン名を変更しておいた方がいい

概要

ボーン名を変更しない場合、アバターのArmatureがどんどん肥大化していって、どのボーンがどの服飾のボーンなのかわからなくなります

その場合、ある服飾がいらなくなったときに、どのボーンを削除すればいいのかわからず、手動で確認していくことになります。

見てください、私のArmature。 まったくわからない。

abandon

手間……手間……!!

「ボーン名の変更」とは?

例えばこの02

clock2020-12-28

アバターのHierarchyにカメラを設定していたら、Build & Publishを押してもアバターアップロード画面が出なくなった

camera

こんな感じにdisplay1~4にカメラを割り当てていたら、VRChat SDKウィンドウ > BuildタブBuild & Publishを押しても、アバターアップロード画面が出なくなりました。

Gameタブには、設定したカメラが表示されてしまっています👇

1

でも大丈夫。 ちゃんとdisplay1を見ると、表示されています。

2

よかった。

clock2020-12-25

brewで環境を更新したらVimでinsertモードに入ったときに固まるようになったので修正した

雑記。

発生した問題

nvim-yarpに依存しているVimプラグインを使うときに? Vimが固まる。

より具体的には「私のVimでsetf markdownしたあとにinsertモードに入ると、数秒ごとにVim固まるようになった」。 (insertモードを離れると、固まらなくなる。)

原因

macのbrewが、私のpython3.8を3.9に更新したこと。

解決

$ brew unlink python@3.9
$ brew link python@3.8

問題発生箇所

多分、nvim-yarp…

clock2020-12-25

gitでまだpushしていないファイルを検出する

重要なやつ 👇

project/scripts/get-root-branch.sh

#!/bin/bash

# もし現在のgitブランチ(ここでfooとします。)がpushされていれば、{remote_name}/fooを返します。
# そうでなければこのブランチのルートとなるブランチ(分岐元)を取得し、それを返します。
#
# このプログラムはまず、リモート名を取得します。
# remoteが複数登録されている場合の適切な処理は未定義です。
# 現在は1番目のリモートを使用するようになっています。

# Returns tags and branches names of the root revision of current.
function root_names () {
  local remote=$1 rev char_not_delim names

  # Parser items
  rev='\w+'
  char_not_delim='[^\)]'
  names="($char_not_delim+)" # 'names' means tags and branches names

  git log --decorate --all --oneline | grep "$remote" | head -1 | sed -r "s/$rev \(($names)\) .*/\1/"
}

# NOTE: Please use nameref feature `local -n result=$1` instead of this global variable if you can use that feature.
names_array=()

# Put given names of glob $2 into $names_array1.
function make_array_of_names() {
  local names=$1 ifs xs i

  # Convert names what are split by ',' to an array.
  ifs=$IFS
  IFS=,
  # shellcheck disable=SC2206
  xs=($names)
  IFS=$ifs

  # Trim heading and trailing spaces
  for (( i=0; i < ${#xs[@]}; i++ )) ; do
    x=$(echo "${xs[$i]}" | sed 's/^ *\| *$//')
    names_array+=("$x")
  done
}

if [[ $(git remote | wc -l) -gt 1 ]] ; then
  echo "Specifying for a remote is not implemented yet. A head remote name will be used instead." > /dev/stderr
fi
remote=$(git remote | head -1)

names=$(root_names "$remote")
make_array_of_names "$names"

for (( i=0; i < ${#names_array[@]}; i++ )) ; do
  name=${names_array[$i]}

  if echo "$name" | grep "^$remote/" > /dev/null ; then
    echo "$name"
    exit 0
  fi
done

exit 1

実際に、pushされていないファイルを検出するやつ 👇

#!/bin/bash

root_dir=$(git rev-parse --show-toplevel)

remote_latest_branch=$(bash -c "$root_dir/scripts/get-root-branch.sh")
current_branch=$(git branch --show-current)
unpushed_files=$(git diff --stat "$remote_latest_branch..$current_branch" --name-only)

# Use $unpushed_files

使用例

~/.git/hooks/pre-push 👇

# textlint for markdown

unpushed_markdown_files=$(echo "$unpushed_files" | grep '\.md$')

if ! npx textlint --config "$root_dir/.textlintrc" "$unpushed_markdown_files" ; then
    exit 1
fi

実行される様子 👇

$ git branch
main

$ npx textlint pushed.md  # push済み、かつtextlintにひっかかるファイル
(textlintにひっかかる)

$ git switch -c foo
$ echo 'GitHubおおおおおん' > new.md  # 未pushの、textlintにひっかかるファイル(ja-space-between-half-and-full-width)

$ git add new.md
$ git commit -m poi

$ git push -u origin/foo

ここでpushed.mdはpre-pushのtextlintにひっかからず、new.mdだけひっかかる。
clock2020-11-23

SCP-1000-■■

  • アイテム番号: SCP-1000-■■
  • オブジェクトクラス: Euclid

特別収容プロトコル

SCP-1000-■■はサイト■■の内の、浴槽付き人型オブジェクト収容室に収容されます。 ただし後述のSCP-1000-■■-Aによる能力の回避のため、監視カメラは撤去されています。

また当オブジェクトは魔術的技法に長けているため、20■■/■■/1…

clock2020-09-13

Udon#でUdonSyncedを使わない方法

目標

Udon#コードでUdonSyncedを使わずに、各ネットワークユーザーのboolの値を同期する。 intもがんばってみる(ただしintに対しては、不完全な対応になります)。

まとめ

以下のようなコードでがんばります。

  • bool向け対応
using UdonSharp;
using UnityEngine;
using VRC.Udon.Common.Interfaces;
using VRC.Udon;

/// <summary>
/// Sets a value with network users.
///
/// NOTE:
/// Don't use DoSetValueTo*() directly.
/// Please use Set() instead.
/// </summary>
public class BoolSync : UdonSharpBehaviour {
    private bool val = false;

    public void Set(bool val) {
        this.SendCustomNetworkEvent(NetworkEventTarget.All, "DoSetValueTo" + val);
    }

    public void DoSetValueToTrue() {
        this.val = true;
    }

    public void DoSetValueToFalse() {
        this.val = false;
    }

    public bool Get() => this.val;
}
  • int向け対応
    • -1, ..., maxValueという範囲への限定的な対応
    • メタプログラミングがんばればint.MinValue, ..., int.MAX_VALUEくらいも可能ではあると思う(Udon#でメタプログラミングできるかは不明)
using UdonSharp;
using UnityEngine;
using VRC.Udon.Common.Interfaces;
using VRC.Udon;

public class IntSync : UdonSharpBehaviour {
    private readonly int MAX_VALUE = something;  // 最大値

    private int val = 0;

    public void Set(int val) {
        if (val > -1 && this.MAX_VALUE < val) {
            Debug.Log($"Illegal argument (the argument must be -1~{this.MAX_VALUE}): {val}");
            return;
        }

        if (val == -1) {
            this.SendCustomNetworkEvent(NetworkEventTarget.All, "DoSetValueToNothing");
        } else {
            this.SendCustomNetworkEvent(NetworkEventTarget.All, "DoSetValueTo" + val);
        }
    }

    public int Get() => this.val;

    /* - - vvvvvvvvvvvvvvv - - */
    /* - - v UNDERGROUND v - - */
    /* - - vvvvvvvvvvvvvvv - - */

    public void DoSetValueToNothing() {
        this.val = -1;
    }

    public void DoSetValueTo0() {
        this.val = 0;
    }

    public void DoSetValueTo1() {
        this.val = 1;
    }

    public void DoSetValueTo2() {
        this.val = 2;
    }

    public void DoSetValueTo3() {
        this.val = 3;
    }

    /* 以下、対応させたい値まで各 */
}

あるUdonSharpBehaviourでそれぞれを使う。

public class Foo : UdonSharpBehaviour {
    public BoolSync paused;
    public BoolSync unPaused;
    public IntSync playing;
}

clock2020-09-10

Spring Tool Suite 4でorg.eclipse.buildship.core.prefsのせいでJAVA_HOMEが設定できなかった

to build

compile error

compile error detail

Java Home: /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home
> Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.

💢💢😡💢💢 ❗❓❓


installed JREs

  • Spring Tool Suite 4 > Preferences

😩❌


debug config

  • プロジェクト名を右クリック > Debug As > Debug Configurations...
  • Spring Boot App > プロジェクト名
  • JRE > Project execution environment

😢❌


environment variables to set

  • 同 > Environment > Environment variables to set
  • JAVA_HOME

❌❌😡❌❌


🤔 oO(……)

$ cd プロジェクト
$ ls -a
.   .git     .mvn       ...
..  .gradle  .settings  ...

.settings 👈 ❓

$ cat .settings/org.eclipse.buildship.core.prefs

...

java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home

...

😦❗

java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home

java.home=/Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home

😒 ……

again

to build

……!

success

Working Directory: /Users/xxxxxx/Repository/rem-server
Gradle user home: /Users/xxxxxx/.gradle

...

Java Home: /Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home

...

BUILD SUCCESSFUL in 13s
5 actionable tasks: 1 executed, 4 up-to-date

👌✨

……

🔥🔥 😬😬😬😬😬 🔥🔥


🙌

clock2020-09-04

【VRChat・メモ】ちゃんとコライダーを設定してるのにオブジェクトが床の下に落ちてしまうときの修正方法

あるGameObjectXが、PlaneなGameObjectPlaneのちょうど上に、positionを設定しました。 このときのHierarchyは下記のようになっていました。

MainScene
|-- X
|-- Plane

そしてXUdonBehavior('Synchronize Positoin')・BoxColliderVRC Pickupを設定しましたが、なぜかPlaneの下に落ちてしまいました。

その後Hierarchyを以下のようにすると、XPlaneの上に乗っかるようになりました。

MainScene
|-- Plane
    |-- X

なんで~~ 😢💦

clock2020-09-01

エクスポートしたいprefabと、その最小限の依存関係のみを持ったunitypackageを作成する

Hi! VRChatにはまった結果ワールド作成沼にもはまり、最近はあんまりVRChatに行っていない、あいやです。

今回はタイトルの通りのunitypackageを作成する方法を、紹介します。

ちなみにこの方法は僕も偶然みつけただけなので、最初びっくりしました!

求める結果

求める結果は下記のような、HabakiRoom.prefabと、その最低限の依存関係のみが入ったunitypackageを作成すること。

1

具体的には――

HabakiRoom.prefabを提供するために、このunitypackageを作たい。 そのためには、unitypackageにHabakiRoom.prefabの依存関係(HabakiRoom…

clock2020-08-16

【VRChat API】favorite済みワールド全てをunfavoriteする

対象読者

  • LinuxのCLIが使える人

やることはCLIの初歩なので、成熟している必要はありません。

各コマンドの解説も本記事で行うので、見てみてください 😎

想定環境

  • Linuxのターミナルエミュレーター(CLI)が使える環境
    • curlコマンドが入っており、jqコマンドを導入できる環境
      • WindowsのWSLやmingw等
      • たぶんcygwinや(がんばれば)Git bashでも可
clock2020-08-11

VRChatのアバターをローカルで簡易テストする

今回は、Unity上でVRChatアバターの簡易テストを行う方法を紹介したいと思います 😎

概要

UnityちゃんのダンスをEmoteに設定し、VRCDeveloperToolのVRCAvatarTesterで再生する。

準備するもの

  • VRCSDK2
  • VRCDeveloperTool
  • ユニティちゃんライブステージ! -Candy Rock Star-
  • つぶしてもいいEmoteをひとつ
clock2020-08-11

VRChatのアバターを新しいアバターとしてアップロードする

問題

僕はあるアバターをアップロードしていました。 そのアバターの名前をXといいます。 そして今回、Xに大きな改変を加えました。

大きな改変を行ったので、それをXと別物のアバター、Yとしてアップロードしようと思いました。 そしていつも通りVRChat SDKウィンドウのBuilderで 'Build & Publish for ZZZ' して、Gameウィンドウでアバター名をY

clock2020-08-02

WIP【Blender未使用】UnityでVRChatアバターの素体(胴体)を入れ替える方法

初めに

この記事では、下記のシークエンスを解説します。

  1. あるアバターから、頭部を切り出す
  2. ある素体(アバターのうち胴体)と、切り出した頭部を結合する

また手順は全てUnity上で行い、Blenderは使用いたしません! (重要。筆者はまだBlenderと和解できておりません 🤔 )

  • 用意すべきもの
    • アバター
    • 素体

今回は一例として、下記の構成で説明します。

clock2020-06-10

【Vimにコントリビュートする人向け】garray_Tの使い方

はじめに

Vimは古典的C言語(多分C99以下の企画)で書かれており、 またライブラリの依存関係を最小に抑えておきたいためでしょうか、 Vimのソースコード内に独自のAPI(structや諸関数)が含まれています。

今回、私はVimへの下記PullRequestを、一年に渡って作成しています。

clock2020-05-23

WindowsでWifiデバイスの設定をいじったら速くなった

今回は、ほぼ個人的メモになります。

11Mbpsから43Mbpsに速くなりました。

changed pref

自室にあるWifi中継機に2.4GHz帯で接続しているので、速くなったのだと思います。 やったー!!

clock2020-05-23

WSL2が仮想化支援機能(Intel-VT)を専有していたため、VMWare Playerで64bit OSがインストールできなかった

先日、VR使用を鑑みた新しいデスクトップPCを購入しました ✨ そのためWindows上、最強のLinux環境を探していたのですが、思わぬところで詰まったので、メモしておきます。

VMWare Playerで64bit OSをインストールするには、Intel-VTが必要

その詰まったところというのが、本稿のタイトルそのものであります。

その解決策は単純で、WSL…

clock2020-05-03

XMonad上のGVimで画面にゴミが出る場合は'renderoptions'

解決策

set renderoptions=type:directxset ambiwidth=double

問題

僕は今、Windows上で最強のLinux環境を求めて、旅をしています。 現在は次のような環境です

  • Windows 10 Home
    • VirtualBox 6.1.2
      • ArchLinux

ArchLinuxのウィンドウマネージャーにはxmonadを使っています。

clock2020-03-19

Vimのtablineに、vim-lspのrunningなserversを表示する

example


以下を設定すると、できる。

.vimrc

set tabline=%!vimrc#tabline#make()

autoload/vimrc/tabline.vim

" 大事なところ!
function vimrc#tabline#make() abort
  let running_lsp_servers = execute(':LspStatus')
    \ ->split('\n')
    \ ->filter({ _, x ->
      \ x !~# 'not running$'
    \ })
    \ ->map({ _, x -> x->split(':')[0] })
    \ ->join(', ')

  return '%1*[%{tabpagenr("$")}]%* '
    \. s:tabs() . ' => '
    \. printf('%6*[${%s}]%*', running_lsp_servers)
endfunction

" 以下、その他設定

" NOTE: http://d.hatena.ne.jp/thinca/20111204/1322932585
function s:tabs()
  let titles = map(range(1, tabpagenr('$')), { _, tabnr ->
    \ vimrc#tabline#tabpage_label(tabnr)
  \ })
  return join(titles) . '%#TabLineFill#%T'
endfunction

function vimrc#tabline#tabpage_label(tabnr)
  let title = gettabvar(a:tabnr, 'title')
  if title !=# ''
    return title
  endif
  let focused_winnr = tabpagewinnr(a:tabnr)
  let curbufnr = tabpagebuflist(a:tabnr)[focused_winnr - 1]
  let file_name = fnamemodify(bufname(curbufnr), ':t')
  let file_name =
    \ (file_name == '')
      \ ? '[NoName]' :
    \ (len(file_name) > 20)
      \ ? (file_name[0:7] . '...' . file_name[-10:-1]) :
    \ file_name

  " Please see `:h TabLineSel` and `:h TabLine`
  let window_num = '[' . len(tabpagebuflist(a:tabnr)) . ']'
  let label_of_a_buf = s:is_stayed_tab(a:tabnr)
    \ ? ('%#TabLineSel#[* ' . s:get_mod_mark_for_window(focused_winnr) . window_num . file_name . ' *]')
    \ : ('%#TabLine#[' . s:get_mod_mark_for_tab(a:tabnr) . window_num . file_name . ']')

  return '%' . a:tabnr . 'T' . label_of_a_buf . '%T%#TabLineFill#'
endfunction

" Do you staying the specified tab?
function s:is_stayed_tab(tabnr) abort
  return a:tabnr is tabpagenr()
endfunction

" Return '+' if the buffer of the specified window is modified
function s:get_mod_mark_for_window(winnr) abort
  return getbufvar(winbufnr(a:winnr), '&modified') ? '+' : ''
endfunction

" Return '+' if one or more a modified non terminal buffer is existent in the taken tab
function s:get_mod_mark_for_tab(tabnr) abort
  let term_buffers = term_list()
  let modified_buffer = s:List.find(tabpagebuflist(a:tabnr), v:null, { bufnr_at_tab ->
    \ !s:List.has(term_buffers, bufnr_at_tab) &&
    \ getbufvar(bufnr_at_tab, '&modified')
  \ })
  return (modified_buffer is v:null) ? '' : '+'
endfunction
clock2020-02-24

Vimをvalgrind付きでビルドして、メモリリークを検出する

$ vim src/testdir/Makefile
diff --git a/src/testdir/Makefile b/src/testdir/Makefile
index bcf2f8c37..cb9af4887 100644
--- a/src/testdir/Makefile
+++ b/src/testdir/Makefile
@@ -18,7 +18,7 @@ REDIR_TEST_TO_NULL = --cmd 'au SwapExists * let v:swapchoice = "e"' > /dev/null
 #   The output goes into a file "valgrind.testN"
 #   Vim should be compiled with EXITFREE to avoid false warnings.
 #   This will make testing about 10 times as slow.
-# VALGRIND = valgrind --tool=memcheck --leak-check=yes --num-callers=25 --log-file=valgrind.$*
+VALGRIND = valgrind --tool=memcheck --leak-check=yes --num-callers=25 --log-file=valgrind.$*
 
 default: nongui
 
$ make clean  # 必要に応じて
$ make -j4 -e CFLAGS='-g3 -O0 -Wall'
$ cd src/testdir
$ make test_template_string  # 実行したいテストを実行する。多分だけど ../vim を実際に操作してもいい
$ cat valgrind.test_template_string

結果

==46735== Memcheck, a memory error detector
==46735== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==46735== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==46735== Command: ../vim -f -u unix.vim -U NONE --noplugin --not-a-term -S runtest.vim test_template_string.vim --cmd au\ SwapExists\ *\ let\ v:swapchoice\ =\ "e"
==46735== Parent PID: 46734
==46735== 
==46735== 
==46735== HEAP SUMMARY:
==46735==     in use at exit: 621,592 bytes in 2,184 blocks
==46735==   total heap usage: 7,098 allocs, 4,914 frees, 2,528,440 bytes allocated
==46735== 
==46735== 3 bytes in 1 blocks are possibly lost in loss record 114 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23A680: concat_str (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18960F: eval5 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188F2E: eval4 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188D80: eval3 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188BD9: eval2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1889F1: eval1 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18C1DC: get_template_string_tv (in /path/to/vim/template-string/src/vim)
==46735==    by 0x189E6B: eval7 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18995E: eval6 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1893E1: eval5 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188F2E: eval4 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188D80: eval3 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188BD9: eval2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1889F1: eval1 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18890D: eval0 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A32B7: ex_let_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A2EB4: ex_let (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34E9F6: call_user_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34F063: call_user_func_check (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34FB4B: call_func (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 6 bytes in 1 blocks are possibly lost in loss record 145 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C971: vim_strsave (in /path/to/vim/template-string/src/vim)
==46735==    by 0x269DC3: get_option_value (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18B318: get_option_tv (in /path/to/vim/template-string/src/vim)
==46735==    by 0x189E29: eval7 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18995E: eval6 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1893E1: eval5 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188F2E: eval4 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188D80: eval3 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188BD9: eval2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1889F1: eval1 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18890D: eval0 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A32B7: ex_let_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A2EB4: ex_let (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE5D8: exe_commands (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 14 bytes in 1 blocks are possibly lost in loss record 216 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C971: vim_strsave (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18E7E2: get_env_tv (in /path/to/vim/template-string/src/vim)
==46735==    by 0x189E8A: eval7 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18995E: eval6 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1893E1: eval5 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188F2E: eval4 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188D80: eval3 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188BD9: eval2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1889F1: eval1 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18890D: eval0 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A32B7: ex_let_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A2EB4: ex_let (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE79A: source_startup_scripts (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAAD5: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 15 bytes in 3 blocks are possibly lost in loss record 219 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C971: vim_strsave (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34BDA1: one_function_arg (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34C116: get_function_args (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3512F6: ex_function (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE5D8: exe_commands (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AB164: vim_main2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAADA: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 28 bytes in 1 blocks are possibly lost in loss record 282 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A76AA: set_var_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18732E: set_var_lval (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A48D8: ex_let_one (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A33B9: ex_let_vars (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188193: next_for_item (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1CAF43: ex_while (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE5D8: exe_commands (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AB164: vim_main2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAADA: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 31 bytes in 1 blocks are possibly lost in loss record 287 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A76AA: set_var_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18732E: set_var_lval (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A48D8: ex_let_one (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A33B9: ex_let_vars (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A3321: ex_let_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A2EB4: ex_let (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34E9F6: call_user_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34F063: call_user_func_check (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34FB4B: call_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34CF61: get_func_tv (in /path/to/vim/template-string/src/vim)
==46735==    by 0x35402D: ex_call (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE5D8: exe_commands (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 32 bytes in 1 blocks are possibly lost in loss record 311 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A76AA: set_var_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18732E: set_var_lval (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A48D8: ex_let_one (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A33B9: ex_let_vars (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A3321: ex_let_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A2EB4: ex_let (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE79A: source_startup_scripts (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAAD5: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 33 bytes in 1 blocks are possibly lost in loss record 313 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C971: vim_strsave (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1904C7: copy_tv (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A6747: get_var_tv (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18A042: eval7 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18995E: eval6 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1893E1: eval5 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188F2E: eval4 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188D80: eval3 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188BD9: eval2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1889F1: eval1 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18890D: eval0 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A32B7: ex_let_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A2EB4: ex_let (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34E9F6: call_user_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34F063: call_user_func_check (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34FB4B: call_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34CF61: get_func_tv (in /path/to/vim/template-string/src/vim)
==46735==    by 0x35402D: ex_call (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 35 bytes in 1 blocks are possibly lost in loss record 315 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A76AA: set_var_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18732E: set_var_lval (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A48D8: ex_let_one (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A33B9: ex_let_vars (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A3321: ex_let_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A2EB4: ex_let (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE79A: source_startup_scripts (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAAD5: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 37 bytes in 2 blocks are possibly lost in loss record 319 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18BE47: get_lit_string_tv (in /path/to/vim/template-string/src/vim)
==46735==    by 0x189D58: eval7 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18995E: eval6 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1893E1: eval5 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188F2E: eval4 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188D80: eval3 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188BD9: eval2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1889F1: eval1 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18890D: eval0 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A32B7: ex_let_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A2EB4: ex_let (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE5D8: exe_commands (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AB164: vim_main2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAADA: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 39 bytes in 1 blocks are possibly lost in loss record 320 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23A680: concat_str (in /path/to/vim/template-string/src/vim)
==46735==    by 0x187C38: tv_op (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1872D3: set_var_lval (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A48D8: ex_let_one (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A33B9: ex_let_vars (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A3321: ex_let_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A2EB4: ex_let (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34E9F6: call_user_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34F063: call_user_func_check (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34FB4B: call_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34CF61: get_func_tv (in /path/to/vim/template-string/src/vim)
==46735==    by 0x35402D: ex_call (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 48 bytes in 1 blocks are possibly lost in loss record 379 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C73B: alloc_clear (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34C7ED: get_lambda_tv (in /path/to/vim/template-string/src/vim)
==46735==    by 0x189DE6: eval7 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18995E: eval6 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1893E1: eval5 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188F2E: eval4 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188D80: eval3 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188BD9: eval2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1889F1: eval1 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18890D: eval0 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A32B7: ex_let_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A2EB4: ex_let (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34E9F6: call_user_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34F063: call_user_func_check (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34FB4B: call_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34CF61: get_func_tv (in /path/to/vim/template-string/src/vim)
==46735==    by 0x35402D: ex_call (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x190F27: ex_execute (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 72 bytes in 3 blocks are possibly lost in loss record 435 of 639
==46735==    at 0x48386AF: malloc (vg_replace_malloc.c:308)
==46735==    by 0x483ADE7: realloc (vg_replace_malloc.c:836)
==46735==    by 0x23D9FD: ga_grow (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34BD69: one_function_arg (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34C116: get_function_args (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3512F6: ex_function (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE5D8: exe_commands (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AB164: vim_main2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAADA: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 75 bytes in 3 blocks are possibly lost in loss record 437 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A76AA: set_var_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18732E: set_var_lval (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A48D8: ex_let_one (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A33B9: ex_let_vars (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A3321: ex_let_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A2EB4: ex_let (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34E9F6: call_user_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34F063: call_user_func_check (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34FB4B: call_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34CF61: get_func_tv (in /path/to/vim/template-string/src/vim)
==46735==    by 0x35402D: ex_call (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x190F27: ex_execute (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34E9F6: call_user_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34F063: call_user_func_check (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34FB4B: call_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34CF61: get_func_tv (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 99 bytes in 3 blocks are possibly lost in loss record 464 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C9B8: vim_strnsave (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1C8B33: eval_vars (in /path/to/vim/template-string/src/vim)
==46735==    by 0x19685F: f_expand (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1940AA: call_internal_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34FBBF: call_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x34CF61: get_func_tv (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188819: eval_func (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18A013: eval7 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18995E: eval6 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1893E1: eval5 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188F2E: eval4 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188D80: eval3 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x188BD9: eval2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1889F1: eval1 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18890D: eval0 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A32B7: ex_let_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A2EB4: ex_let (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 558 bytes in 17 blocks are possibly lost in loss record 545 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A76AA: set_var_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x18732E: set_var_lval (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A48D8: ex_let_one (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A33B9: ex_let_vars (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A3321: ex_let_const (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1A2EB4: ex_let (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE5D8: exe_commands (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AB164: vim_main2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAADA: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 560 bytes in 2 blocks are possibly lost in loss record 546 of 639
==46735==    at 0x483AD7B: realloc (vg_replace_malloc.c:836)
==46735==    by 0x23D9FD: ga_grow (in /path/to/vim/template-string/src/vim)
==46735==    by 0x35267D: ex_function (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE5D8: exe_commands (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AB164: vim_main2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAADA: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 749 bytes in 2 blocks are possibly lost in loss record 558 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C73B: alloc_clear (in /path/to/vim/template-string/src/vim)
==46735==    by 0x352C65: ex_function (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE5D8: exe_commands (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AB164: vim_main2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAADA: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 1,352 bytes in 4 blocks are possibly lost in loss record 578 of 639
==46735==    at 0x483AD7B: realloc (vg_replace_malloc.c:836)
==46735==    by 0x23D9FD: ga_grow (in /path/to/vim/template-string/src/vim)
==46735==    by 0x35267D: ex_function (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE5D8: exe_commands (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AB164: vim_main2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAADA: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 1,425 bytes in 4 blocks are possibly lost in loss record 584 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C73B: alloc_clear (in /path/to/vim/template-string/src/vim)
==46735==    by 0x352C65: ex_function (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE5D8: exe_commands (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AB164: vim_main2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAADA: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 1,676 bytes in 68 blocks are possibly lost in loss record 592 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C971: vim_strsave (in /path/to/vim/template-string/src/vim)
==46735==    by 0x352694: ex_function (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE5D8: exe_commands (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AB164: vim_main2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAADA: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== 3,363 bytes in 122 blocks are possibly lost in loss record 604 of 639
==46735==    at 0x483877F: malloc (vg_replace_malloc.c:309)
==46735==    by 0x23C82D: lalloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C6D8: alloc (in /path/to/vim/template-string/src/vim)
==46735==    by 0x23C971: vim_strsave (in /path/to/vim/template-string/src/vim)
==46735==    by 0x352694: ex_function (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1CDE: do_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D10C5: cmd_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x2D1111: ex_source (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BE521: do_one_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BB840: do_cmdline (in /path/to/vim/template-string/src/vim)
==46735==    by 0x1BADCE: do_cmdline_cmd (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AE5D8: exe_commands (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AB164: vim_main2 (in /path/to/vim/template-string/src/vim)
==46735==    by 0x3AAADA: main (in /path/to/vim/template-string/src/vim)
==46735== 
==46735== LEAK SUMMARY:
==46735==    definitely lost: 0 bytes in 0 blocks
==46735==    indirectly lost: 0 bytes in 0 blocks
==46735==      possibly lost: 10,250 bytes in 243 blocks
==46735==    still reachable: 611,342 bytes in 1,941 blocks
==46735==         suppressed: 0 bytes in 0 blocks
==46735== Reachable blocks (those to which a pointer was found) are not shown.
==46735== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==46735== 
==46735== For lists of detected and suppressed errors, rerun with: -s
==46735== ERROR SUMMARY: 22 errors from 22 contexts (suppressed: 0 from 0)

ここでdefinitely lostが0でないようなら、 X bytes in X blocks are definitely lost in loss record X of X と書かれたコールスタック内にあるメモリリークを修正する必要があります。

==46735== LEAK SUMMARY:
==46735==    definitely lost: 0 bytes in 0 blocks
clock2020-02-21

Firebase AuthenticationユーザーのdisplayNameは、Firestore rules上ではnameとして定義される

Firebase Authenticationユーザーを、次のように登録したとします。

import * as Firebase from 'firebase'

const auth = Firebase.auth()
const email = someEmail
const password = somePassword

try {
  const credential = await auth.createUserWithEmailAndPassword(email, password)
  const user = credential.user
  if (user === null) {
    throw new Error(
      `creating user for authentication was success, but nobody is logging in. something wrong! credential: ${credential}`
    )
  }

  await user.updateProfile({ displayName: 'Haskell' })  // !
  await user.sendEmailVerification()
} catch (e) {
  if (e instanceof Error && /The email address is already in use by another account./.test(e.message)) {
    throw new Error(`メールアドレス「${account.email}」は既に使用されています。`)
  }
  throw new Error(e)
}

また、次のようにFirestoreコレクションへ、ドキュメントを追加したとします。

const ref = await Firebase.firestore()
  .collection('accounts')
  .doc('Haskell')  // !
const doc = await ref.get()

if (doc.exists) {
  throw new Error(`アカウント名「${account.name}」は既に使用されています。`)
}

ref.set(account)

この際、下記コードによりref.get()できるようにするには

const ref = await Firebase.firestore()
  .collection('accounts')
  .doc('Haskell')  // !
const doc = ref.get()

Firestore rulesへの下記設定が必要です。

rules_version = '2';

service cloud.firestore {
    match /databases/{database}/documents {
        match /accounts/{account} {
            allow create;
            allow read: if account == request.auth.token.name;
            // 誤り ↓
            // allow read: if account == request.auth.token.displayName;
        }
    }
}

この仕様、どこに書いてあります……???

clock2019-12-14

技書博2(技術書同人誌博覧会2)にサークル参加してきました!

技書博って?

頒布物内容

内容は技術書典7のときと同じなので、詳しくはこちらをご覧ください :bow:

売り上げ

  • せつラボ 〜圏論の基本〜: 19冊(19〜23)
  • 矢澤にこ先輩といっしょに代数!: 6冊(6〜8)

clock2019-12-04

Haskell Day 2019でスタッフ&30分登壇をしてきました!

去年に引き続き、今回もHaskell Dayで30分登壇をしてきました。

Haskell Day 2019?

今年も、日本最大級のHaskellコミュニティーイベント、「Haskell Day」を開催します! Haskell-jp主催の元、「関数型プログラミング」に必ずしもとらわれないHaskellの魅力を、様々な面から伝える会にします!

clock2019-12-02

VimConf2019でスタッフ&LTをしました

VimConf 2019で、「VimConfスタッフ」及び「発表(LT枠・5分)」をしてきました!

VimConf 2019?

もう一ヶ月前じゃん! ちょっと!

何をやったの?

スタッフ

VimConfスタッフとして、文章周りを担当しました。

clock2019-10-26

systemd-networkdを使うときはdhcpcdを切る

でないと wifi-menu でAPに、うまく繋がらなない。

clock2019-09-23

技術書典7で数学入門書(圏論)を頒布してきました!(計上報告等)

技術書典7について

技術書典7とは、2019-09-22に開催された、技術書専門の同人誌即売会です。

頒布した本

技術書典7では「せつラボ 〜圏論の基礎〜」という本を頒布してきました! 技術書典6で頒布したものの、大幅修正バージョンです。

clock2019-09-01

【サンプルpdfあり】技術書典7にて圏論入門小説を頒布します!【え20C】

概要

技術書典7にて、圏論入門小説を頒布します!(え20C)

  • タイトル: せつラボ 〜圏論の基本〜
  • ページ数: 128p 158p!(第二版につき増量!)
  • 価格: 1,000円

これは第一版に加え、大幅な改稿と、Haskellの章の追加を行った第二版です。

第一版を買ってくださった方も技術書典7の開催時以降、「物理書籍の巻末にあるダウンロードURL…

clock2019-07-18

Vim本体にコントリビュートする際の僕の手順

1. デバッグビルド用のconfigureをシェルスクリプトにしておく

これは最小限のビルドオプションなので、適宜修正。

#!/bin/bash
configure=$(cat << EOS
./configure \
    --prefix=/usr/local/ \
    --enable-fail-if-missing \
    --enable-gui=no \
    --enable-multibyte=yes \
    --enable-perlinterp=no \
    --enable-pythoninterp=no \
    --enable-python3interp=no \
    --enable-rubyinterp=no \
    --enable-luainterp=no \
    --with-lua-prefix=/usr \
    --with-luajit \
    --enable-cscope=yes \
    --with-features=huge \
    --with-compiledby=aiya000 \
    --enable-terminal
EOS
)

if [ -f ./configure ] ; then
    echo "$configure"
    eval "$configure"
else
    echo './configure cannot be found'
fi

2. ccacheでビルドを高速化する

~/.zshrcあたり。

export USE_CCACHE=1
export $CCACHE_DISABLE=0
export CCACHE_DIR=$SUGOI_IPPAI_YOURYO_ARU_TOKO

なんか今みたら、うまく動いてなかったっぽい……。

誰かVimでccacheを使う方法わかったら、教えて!

3. eval.cとかを修正する

がんばります。

clock2019-07-14

VimをSanitizer付きでビルドして、メモリリークを検出する

 vim-jpでichizokさんに指南をいただきました。 ありがとうございます 😎

$ cd /path/to/vim
$ SANITIZER_CFLAGS="-g -O1 -DABORT_ON_INTERNAL_ERROR -DEXITFREE -fsanitize=address -fno-omit-frame-pointer"
$ ASAN_OPTIONS="print_stacktrace=1 log_path=asan"
$ make

Starting make in the src directory.
If there are problems, cd to the src directory and run make there
cd src && make first
make[1]: Entering directory '/path/to/vim/template-string/src'
ccache gcc -c -I. -Iproto -DHAVE_CONFIG_H     -g3 -O0 -Wall  -g -O1 -DABORT_ON_INTERNAL_ERROR -DEXITFREE -fsanitize=address -fno-omit-frame-pointer      -o obj
ects/eval.o eval.c
make[2]: Entering directory '/path/to/vim/template-string/src/po'
make[2]: Nothing to be done for 'first'.

.
.
.

$ cd src/testdir
$ make test_template_string

rm -f test_template_string.res test.log messages
make -f Makefile test_template_string.res
make[1]: Entering directory '/path/to/vim/src/testdir'
make[1]: *** [Makefile:162: test_template_string.res] Error 1
make[1]: Leaving directory '/path/to/vim/src/testdir'
make: *** [Makefile:76: test_template_string] Error 2

$ ls asan.*
asan.12870

$ cat asan.12870

結果

cat asan.12870
=================================================================
==35931==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 520 byte(s) in 1 object(s) allocated from:
    #0 0x563181203441  (/path/to/vim/template-string/src/vim+0x233441)
    #1 0x7f590adfa521  (/usr/lib/libXt.so.6+0x13521)

Indirect leak of 21152 byte(s) in 1 object(s) allocated from:
    #0 0x563181203441  (/path/to/vim/template-string/src/vim+0x233441)
    #1 0x7f590a88d291  (/usr/lib/libxcb.so.1+0xc291)

Indirect leak of 16384 byte(s) in 1 object(s) allocated from:
    #0 0x563181203441  (/path/to/vim/template-string/src/vim+0x233441)
    #1 0x7f590acd7c13  (/usr/lib/libX11.so.6+0x30c13)

Indirect leak of 5040 byte(s) in 2 object(s) allocated from:
    #0 0x563181203441  (/path/to/vim/template-string/src/vim+0x233441)
    #1 0x7f590acd7f7d  (/usr/lib/libX11.so.6+0x30f7d)

Indirect leak of 4688 byte(s) in 1 object(s) allocated from:
    #0 0x563181203441  (/path/to/vim/template-string/src/vim+0x233441)
    #1 0x7f590acd78bf  (/usr/lib/libX11.so.6+0x308bf)
    #2 0x5631814de807  (/path/to/vim/template-string/src/vim+0x50e807)
    #3 0x5631814af9ae  (/path/to/vim/template-string/src/vim+0x4df9ae)
    #4 0x563181718296  (/path/to/vim/template-string/src/vim+0x748296)
    #5 0x563181714ff6  (/path/to/vim/template-string/src/vim+0x744ff6)
    #6 0x7f590a8db152  (/usr/lib/libc.so.6+0x27152)

Indirect leak of 2372 byte(s) in 1 object(s) allocated from:
    #0 0x563181203612  (/path/to/vim/template-string/src/vim+0x233612)
    #1 0x7f590a88d47c  (/usr/lib/libxcb.so.1+0xc47c)

Indirect leak of 628 byte(s) in 1 object(s) allocated from:
    #0 0x563181203289  (/path/to/vim/template-string/src/vim+0x233289)
    #1 0x7f590acd83f1  (/usr/lib/libX11.so.6+0x313f1)

Indirect leak of 168 byte(s) in 1 object(s) allocated from:
    #0 0x563181203441  (/path/to/vim/template-string/src/vim+0x233441)
    #1 0x7f590acd81a0  (/usr/lib/libX11.so.6+0x311a0)

Indirect leak of 160 byte(s) in 1 object(s) allocated from:
    #0 0x563181203289  (/path/to/vim/template-string/src/vim+0x233289)
    #1 0x7f590acc67cc  (/usr/lib/libX11.so.6+0x1f7cc)

Indirect leak of 152 byte(s) in 1 object(s) allocated from:
    #0 0x563181203441  (/path/to/vim/template-string/src/vim+0x233441)
    #1 0x7f590ad3db8f  (/usr/lib/libX11.so.6+0x96b8f)

Indirect leak of 132 byte(s) in 6 object(s) allocated from:
    #0 0x563181203289  (/path/to/vim/template-string/src/vim+0x233289)
    #1 0x7f590adfa2f5  (/usr/lib/libXt.so.6+0x132f5)

Indirect leak of 128 byte(s) in 1 object(s) allocated from:
    #0 0x563181203441  (/path/to/vim/template-string/src/vim+0x233441)
    #1 0x7f590acd7e2c  (/usr/lib/libX11.so.6+0x30e2c)

Indirect leak of 128 byte(s) in 1 object(s) allocated from:
    #0 0x563181203441  (/path/to/vim/template-string/src/vim+0x233441)
    #1 0x7f590acd180c  (/usr/lib/libX11.so.6+0x2a80c)

Indirect leak of 112 byte(s) in 1 object(s) allocated from:
    #0 0x563181203441  (/path/to/vim/template-string/src/vim+0x233441)
    #1 0x7f590acd7efd  (/usr/lib/libX11.so.6+0x30efd)

Indirect leak of 104 byte(s) in 1 object(s) allocated from:
    #0 0x563181203441  (/path/to/vim/template-string/src/vim+0x233441)
    #1 0x7f590ace6f3f  (/usr/lib/libX11.so.6+0x3ff3f)

Indirect leak of 72 byte(s) in 1 object(s) allocated from:
    #0 0x563181203441  (/path/to/vim/template-string/src/vim+0x233441)
    #1 0x7f590acd7c76  (/usr/lib/libX11.so.6+0x30c76)

Indirect leak of 48 byte(s) in 1 object(s) allocated from:
    #0 0x563181203289  (/path/to/vim/template-string/src/vim+0x233289)
    #1 0x7f590ace7055  (/usr/lib/libX11.so.6+0x40055)

Indirect leak of 48 byte(s) in 1 object(s) allocated from:
    #0 0x563181203289  (/path/to/vim/template-string/src/vim+0x233289)
    #1 0x7f590ace703e  (/usr/lib/libX11.so.6+0x4003e)

Indirect leak of 40 byte(s) in 1 object(s) allocated from:
    #0 0x563181203289  (/path/to/vim/template-string/src/vim+0x233289)
    #1 0x7f590ace914e  (/usr/lib/libX11.so.6+0x4214e)

Indirect leak of 32 byte(s) in 1 object(s) allocated from:
    #0 0x563181203289  (/path/to/vim/template-string/src/vim+0x233289)
    #1 0x7f590a88faa7  (/usr/lib/libxcb.so.1+0xeaa7)

Indirect leak of 32 byte(s) in 1 object(s) allocated from:
    #0 0x563181203612  (/path/to/vim/template-string/src/vim+0x233612)
    #1 0x7f590a89056f  (/usr/lib/libxcb.so.1+0xf56f)

Indirect leak of 24 byte(s) in 1 object(s) allocated from:
    #0 0x563181203289  (/path/to/vim/template-string/src/vim+0x233289)
    #1 0x7f590ace7656  (/usr/lib/libX11.so.6+0x40656)

Indirect leak of 21 byte(s) in 1 object(s) allocated from:
    #0 0x563181203289  (/path/to/vim/template-string/src/vim+0x233289)
    #1 0x7f590acd7d95  (/usr/lib/libX11.so.6+0x30d95)

Indirect leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x563181203289  (/path/to/vim/template-string/src/vim+0x233289)
    #1 0x7f590a89092e  (/usr/lib/libxcb.so.1+0xf92e)

Indirect leak of 10 byte(s) in 1 object(s) allocated from:
    #0 0x563181180e99  (/path/to/vim/template-string/src/vim+0x1b0e99)
    #1 0x7f590acd181d  (/usr/lib/libX11.so.6+0x2a81d)

Indirect leak of 3 byte(s) in 1 object(s) allocated from:
    #0 0x563181180e99  (/path/to/vim/template-string/src/vim+0x1b0e99)
    #1 0x7f590acd78d4  (/usr/lib/libX11.so.6+0x308d4)

SUMMARY: AddressSanitizer: 52214 byte(s) leaked in 32 allocation(s).

 突然ですが現在、僕はVimにtemplate string対応を入れようと、活動しております。

clock2019-07-04

NativeScriptの型不安全なObservableを型安全にする

 NativeScriptのObservableは、プロパティへの代入(っぽいメソッド)から、処理をフックすることができるクラスです。 MVVM…

clock2019-06-26

Vimのソース内で自作した関数の結果を確認する

 Vimにコントリビュートしたいけど、 「char_u*って? typval_Tってなんじゃい? eval1? :h expr1?」 っていう状態だった。

 とりあえず、自作関数で動作を確認したい。

    static void
mine(void)
{
    static int b = 0;
    if (!b) {
	b = 1;
	char_u* x = vim_strsave((char_u*) "10");
	typval_T y = { VAR_UNKNOWN, 0, {0} };
	eval1(&x, &y, 1);
	printf("\n");  // ここをX行目と仮定する
    }

  1. eval.hのex_echo関数をエディタで開く。
  2. その上に上記のmine関数を定義する。
    • 名前はmineでなくてもよい。内容もお好みで。
  3. ex_echo関数の変数宣言句の下で、mineを呼び出す。
    • /*
       * ":echo expr1 ..."	print each argument separated with a space, add a
       *			newline at the end.
       * ":echon expr1 ..."	print each argument plain.
       */
          void
      ex_echo(exarg_T *eap)
      {
          char_u	*arg = eap->arg;
          typval_T	rettv;
          char_u	*tofree;
          char_u	*p;
          int		needclr = TRUE;
          int		atstart = TRUE;
          char_u	numbuf[NUMBUFLEN];
          int		did_emsg_before = did_emsg;
          int		called_emsg_before = called_emsg;
      
          mine();  // ha-ya!
      
          if (eap->skip)
          ++emsg_skip;
          while (*arg != NUL && *arg != '|' && *arg != '\n' && !got_int)
  4. CLIでmake
  5. Vimで:packadd termdebug, :execute 'Termdebug' expand('~/path/to/vim/src/vim')
  6. gdbウィンドウでb mineからのrun -u NONE --noplugin
  7. Vimウィンドウで:echo 10
    • 10でなくてもよい。なんでもいいからex_echoを呼び出す。
  8. gdbウィンドウでnして、mineのX行目へ進む。
    • X行目については、上記mineの定義を参照。
  9. gdbウィンドウで結果を確認する。
    • Breakpoint 1, mine () at eval.c:8897
      8897    {
      (gdb) n
      8899        if (!b) {
      (gdb) 
      8900            b = 1;
      (gdb) 
      8901            char_u* x = vim_strsave((char_u*) "10");
      (gdb) 
      8902            typval_T y = { VAR_UNKNOWN, 0, {0} };
      (gdb) 
      8903            eval1(&x, &y, 1);
      (gdb) 
      8904            printf("\n");
      (gdb) p x
      $1 = (char_u *) 0x5555558cbb52 ""
      (gdb) p y
      $2 = {v_type = VAR_NUMBER, v_lock = 0 '\000', vval = {v_number = 10, v_float = 4.9406564584124654e-323, v_string = 0xa <error: Cannot access memory at address
       0xa>, v_list = 0xa, v_dict = 0xa, v_partial = 0xa, v_job = 0xa, v_channel = 0xa, v_blob = 0xa}}
      (gdb) p y.v_type
      $3 = VAR_NUMBER
      (gdb) p y.vval.v_number
      $4 = 10
clock2019-05-05

銭けっと(5/3)にて数学入門書(圏論)を頒布してきました!

Table of Contents

概要

 「銭けっと」というイベントで、数学入門書を頒布してきました 😳

頒布した本

clock2019-04-18

銭けっと(5/3)にて数学入門書(圏論)を頒布します!

概要

 銭けっと(5/3)にて数学入門書(圏論)を頒布します!

頒布物

 技術書典6で頒布した新刊です。

既刊のにこ本も持っていきます!

menu

  • 新刊・既刊ともに、物理本は少数のみ持っていきます。多分すぐ売り切れちゃう。ごめんなさい!
clock2019-04-17

技術書典6で数学入門書(圏論)を頒布してきました!

Table of Contents

技術書典6について

 技術書典6とは、2019-04-14に開催された、技術書専門の同人誌即売会です。

頒布した本

 技術書典6では「せつラボ 〜圏論の基礎〜」という本を頒布してきました!

clock2019-03-29

正誤表 - 矢澤にこ先輩といっしょに代数!

 矢澤にこ先輩といっしょに代数!の誤りについての、Web正誤表です。 逐次、更新されます。

誤り章 誤り内容 正しくは 修正バージョン
用語、前提知識の説明 > 数の種類 0/3や0/1000のように分子ではなくて分母が0でも有理数よ 0/3や0/1000のように分子が0でも有理数よ 第2版
モノイド > モノイドの具体例 > 真姫「真理値についても単純ね」 True && False = False, False && True = True True && False = False, False && True = False 第2版
半群 > 結合法則 > 半群 = 足し合わせることができる構造 1〜100全てを含んだ式を考えるなら、パターンは99通りもあるわ。 1〜100全てを含んだ式を考えるなら、パターンは**……いっぱい**あるわ! 第2版
clock2019-03-16

【サンプルpdfあり】技術書典6にて圏論入門小説を頒布します!【こ11】

概要

 技術書典6にて、圏論入門小説を頒布します!(こ11)

  • タイトル: せつラボ 〜圏論の基本〜
  • ページ数: 128p
  • 価格: 1,000円

サークルページ

サークルカット

サンプル(お試し本)

紹介

 数学未入門者を対象とした、小説です。 圏論への入門を手引きします!

  • 圏とは?
  • 関手とは?
  • どんなところが楽しいの?

 集合論・Haskell…

clock2019-03-16

正誤表 - せつラボ 〜圏論の基本〜

Special Thanks

 @tadsanさんは当日、弊サークルの売り子さんをしてくださり、売り上げに多大な貢献をしてくださりました。

にも関わらず、第一版の頒布時点での、本書のSpecial Thanksに書かれていませんでした……。 ですのでこの場をお借りして、感謝をあげさせてください。

 @tadsan…

clock2019-02-08

List<Either<E, A>>からEither<List<E>, List<A>>を取らない

List<Either<E, A>>から「全てのleft値 or 全てのright値」を取るときは、左にNonEmptyList<E>をかけること。

結論

Either<List<E>, List<A>>ではなくEither<NonEmptyList<E>, List<A>>を使いましょう!

import arrow.core.Either
import arrow.core.left
import arrow.core.right
import arrow.data.NonEmptyList

/**
 * leftが1つでもあれば全てのleftを。
 * そうでなければ全てのrightを返します。
 *
 * ```
 * >>> val xs = listOf<Either<Unit, Unit>>()
 * >>> xs.collect()
 * Right(b=[])
 * ```
 */
fun <E, T> List<Either<E, T>>.collect(): Either<NonEmptyList<E>, List<T>> {
    val (lefts, rights) = this.partition { it is Either.Left }
    return when (val head = lefts.getOrNull(0)) {
        null -> rights.map(::unsafeRight).right()
        else -> NonEmptyList(head, lefts.drop(1).map(::unsafeLeft)).left()
    }
}

private fun <E, T> unsafeLeft(self: Either<E, T>): E = (self as Either.Left).a
private fun <E, T> unsafeRight(self: Either<E, T>): T = (self as Either.Right).b

対象言語

Either<E, A>List<T>がある言語全般。

以下Kotlinでは、kotlinに基本的・応用的な代数的データ型を提供してくれるライブラリarrowを用います。

(僕の推しライブラリなので、見てみてください! まだドキュメントが充実していない気はしますが、着々と進んでいるようです。)

概要

List<Either<E, A>>

clock2019-01-25

Google Drive REST API Javaで検索条件を指定する

Java Quickstart - Drive REST API - Google DevelopersOverview (Drive API v3 (Rev. 136) 1.25.0)に、 /drive/v3/filesでの検索条件指定の方法が書かれていない気がするので、 迷ってしまいましたので、メモをしておきます。

結論ですが、Drive.Files.List#setQ(String)を使います :green_salad:

clock2019-01-04

2018年振り返り(Haskell Day・.vimconf.swp・技術書典5・...)

あけましておめでとうございます 🎉

もう2019年になってしまいましたが、2018年の成果をまとめます。

ペロくん

発表

今年の後半はいくつかのLTと、短くない登壇をしました。

clock2018-12-26

Vim scriptに静的型付けを導入するTime script

ハロー 🤟🙄🤟

この記事は IQ1 Advent Calendar 2018 - Adventar 5日目の記事です!

さてIQ1の皆さんにおきましてはIQが1だと思いますので、 プログラミングでの誤りを検知するために静的型付き言語を使うことが必要な場合が多いかと思います。

でもVimプラグインを作るには(主に)動的型付き言語であるVim scriptを書く必要があります。

そこでTime…

clock2018-12-02

Vim Advent Calendar 2018ボツ記事(vital.vimで関数型プログラミング入門)

最近はvital.vimというVim scriptの準標準ライブラリでData.List・Data.OptionalやData.Eitherを開発していたのですが、 Vim scriptのような動的型付き言語でnullや例外を使わずにoptionalやeitherを使う利点がわからなくなり、 絶望したので以下の記事をボツにしました。

ここに供養する。

vital.vimで関数型プログラミング入門

clock2018-10-10

技術書展5で代数的構造の本を頒布してきました🤟🙄🤟

 サークルとしては初参加だった技術書典5での、 頒布について報告です 🐕

頒布内容

サークルカット

  1. 紙版
  2. ダウンロードカード
  3. 完全ダウンロード版(現在販売中)

一律1000円での頒布です。

売れた部数(用意した部数)

  • 紙版: 100 (100)
  • ダウンロードカード: 62 (300)
  • 完全ダウンロード版(10月10日現在): 10

紙版の完売はたしか1…

clock2018-09-12

技術書典5に参加します!(か74)

サンプル(お試し本)

サークルページ

サークルカット

頒布物

「矢澤にこ先輩といっしょに代数!」 というタイトルで、 以下のような人に向けての本を頒布します!

  • 数学・代数の雰囲気をゆるく知りたい
  • 軽いHaskellを知りたい
  • なんでもいいから技術系にこまきが読みたい

以下サンプルです、 よろしくお願いします 🐕


sample1


sample2


sample3


sample4


sample5


sample6


Moggi…

clock2018-08-17

sbt-doctestはテストプロジェクトのdoctestを見ない

 doctestは最高ですから(Scalaだけに)Scalaにも存在します。

ここでこれを導入したプロジェクトのうちテストプロジェクト ./src/test/poi/yudachi/sugar があるとして、この ./src/test/poi/yudachi/sugar/PoiTest.scala にdoctestを記述しておいても実行されませんでした。

っぽい!

clock2018-07-31

gitの「Could not execute editor」が出たときは$GIT_EDITORを設定する

$ GIT_EDITOR=nvim git rebase --interact

起承結

$ git rebase --interact
/usr/local/Cellar/git/2.16.1/libexec/git-core/git-rebase--interactive: line 267: /Users/aiya000/poi/.git/rebase-merge/git-rebase-todo: Permission denied
Could not execute editor

って言われてrebase -iできない。 なんかちょっと前もこれで困ってrm -rf git-repo && git clone https://foo.bar/git-repo.gitとかした気がする。

皆さんけっこうgit config core.editor /path/to/your_editorのようにyour_editorへのフルパス指定で解決してるみたいでしたが、 僕は解決できず。

$ GIT_EDITOR=nvim git rebase --interact

で解決できました。

最後にecho 'export GIT_EDITOR=nvim' >> .zprofileみたいな感じで完全になりました。 最強。

clock2018-07-25

Happyの%tokenではより一般的な形式を下にしなきゃだめ

正誤

正しい

%token
  ...
  ...
  natType  { (TokenAnIdent "Nat", _)   }
  boolType { (TokenAnIdent "Bool", _)  }
  ident    { (TokenAnIdent $$, _)      }

誤り

%token
  ...
  ident    { (TokenAnIdent $$, _)      }
  ...
  natType  { (TokenAnIdent "Nat", _)   }
  boolType { (TokenAnIdent "Bool", _)  }

これはhappy製の単純型付きラムダ計算パーサーの、トークン宣言部です。

「正しい」のようにしないと、このような実行時エラーが起きます。

>>> parse "\\x:Nat.10"
got a token "Nat",
but [natType, boolType] are expected.

"Nat" near_equal natTypeですが、先にidentの方にマッチするために、"Nat"がidentだと判断されています 🤘🙄🤘

実際の修正例

clock2018-06-30

VimのQuickFixでelm-makeの結果を表示する設定を書いた

 ソースはこちらに上げました 👇

 ☝

 elm-makeはエラー情報をjson形式で出力するという最高の機能があるので、逆に'errroformat'の行単位でエラーを解析するVimのQuickFixではうまく解析できません。
(elm…

clock2018-06-30

mtlのExceptTを使うべき。EitherTでもtransformersのExceptTでもなく。

 EitherのMonadTrans相当のものを使いたいときに、何を使うべきか毎回忘れてしまうので、メモしておきます。

下記の理由により現在は、eitherのEitherTまたはtransformersのExceptTではなく、mtlのExceptTを使うべきです。

  • eitherのEitherTはDeprecated
  • transformersのExceptTはMonadExcept e m | m -> s相当のものがないので GenralizedNewtypeDerivingすると効力を無くす(deriving MonadExcept Eできない)
  • mtlのExceptTにはMonadError e m | m -> eがある
clock2018-06-20

ScopedTypeVariables下の1ランク多相で型が合わないとき

まとめ

 forallを指定してあげると、一連のa, bが固定されてくれます。

f :: forall a b. Eq b => (a -> b) -> (a -> b) -> a -> Bool

解説

 以下のようなコードを書くと

{-# LANGUAGE ScopedTypeVariables #-}

f :: Eq b => (a -> b) -> (a -> b) -> a -> Bool
f g h x =
  let y = g x :: b
      z = h x :: b
  in y == z

main :: IO ()
main = pure ()

以下のようなエラーがでます。 「g xによって推論されたその型b'と、指定されたその型bが同一ではない」の意です。

意図として 「g x :: bbは、fの型で指定されたbそのものである」 ということを指定したつもりなのだけど…。

/tmp/nvimNLJJ6T/148.hs:5:11: error:
    • Couldn't match expected type ‘b2’ with actual type ‘b’
      ‘b’ is a rigid type variable bound by
        the type signature for:
          f :: forall b a. Eq b => (a -> b) -> (a -> b) -> a -> Bool
        at /tmp/nvimNLJJ6T/148.hs:3:6
      ‘b2’ is a rigid type variable bound by
        an expression type signature:
          forall b2. b2
        at /tmp/nvimNLJJ6T/148.hs:5:18
    • In the expression: g x :: b
      In an equation for ‘y’: y = g x :: b
      In the expression:
        let
          y = g x :: b
          z = h x :: b
        in y == z
    • Relevant bindings include
        h :: a -> b (bound at /tmp/nvimNLJJ6T/148.hs:4:5)
        g :: a -> b (bound at /tmp/nvimNLJJ6T/148.hs:4:3)
        f :: (a -> b) -> (a -> b) -> a -> Bool
          (bound at /tmp/nvimNLJJ6T/148.hs:4:1)

/tmp/nvimNLJJ6T/148.hs:6:11: error:
    • Couldn't match expected type ‘b2’ with actual type ‘b’
      ‘b’ is a rigid type variable bound by
        the type signature for:
          f :: forall b a. Eq b => (a -> b) -> (a -> b) -> a -> Bool
        at /tmp/nvimNLJJ6T/148.hs:3:6
      ‘b2’ is a rigid type variable bound by
        an expression type signature:
          forall b2. b2
        at /tmp/nvimNLJJ6T/148.hs:6:18
    • In the expression: h x :: b
      In an equation for ‘z’: z = h x :: b
      In the expression:
        let
          y = g x :: b
          z = h x :: b
        in y == z
    • Relevant bindings include
        h :: a -> b (bound at /tmp/nvimNLJJ6T/148.hs:4:5)
        g :: a -> b (bound at /tmp/nvimNLJJ6T/148.hs:4:3)
        f :: (a -> b) -> (a -> b) -> a -> Bool
          (bound at /tmp/nvimNLJJ6T/148.hs:4:1)

/tmp/nvimNLJJ6T/148.hs:7:6: error:
    • Could not deduce (Eq a0) arising from a use of ‘==’
      from the context: Eq b
        bound by the type signature for:
                   f :: Eq b => (a -> b) -> (a -> b) -> a -> Bool
        at /tmp/nvimNLJJ6T/148.hs:3:1-46
      The type variable ‘a0’ is ambiguous
      These potential instances exist:
        instance Eq Ordering -- Defined in ‘GHC.Classes’
        instance Eq Integer
          -- Defined in ‘integer-gmp-1.0.0.1:GHC.Integer.Type’
        instance Eq a => Eq (Maybe a) -- Defined in ‘GHC.Base’
        ...plus 22 others
        ...plus 7 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: y == z
      In the expression:
        let
          y = g x :: b
          z = h x :: b
        in y == z
      In an equation for ‘f’:
          f g h x
            = let
                y = ...
                z = ...
              in y == z

ということで、確かに 「g x :: bbは、fの型で指定されたb

clock2018-05-26

HaskellerだけどBoothにマッハ新書出してみた(矢澤にこ先輩と一緒にモナドモナド!)

宣伝

 今流行りの(?)マッハ新書に「矢澤にこ先輩と一緒にモナドモナド!」を出品してみました!

 これはC92で頒布された「簡約!? λカ娘 10 - 参照透明な海を守る会」 に載せていただいた内容を改修したものです。

clock2018-05-22

gradle buildの出力をVimのQuickFixに表示してエラー箇所にジャンプする

 vim-quickrunに依存する。

result

 .vimrcに以下を記述。

let g:quickrun_config = {
    \ 'gradle_build': {
        \ 'runner': 'vimproc',
        \ 'outputter': 'quickfix',
        \ 'command': 'gradle',
        \ 'cmdopt': 'build',
        \ 'exec': '%c %o',
    \ },
\}

 .vim/after/ftplugin/kotlin.vim や .vim/after/ftplugin/java.vim に以下を記述。

let &errorformat = '%t: %f: (%l\, %c): %m'

 あとは.ktや.javaのファイル内で :QuickRun gradle_build すると 上記画像のように表示されるので、 <C-m> キーなどを押すと 当該ファイル内の当該エラー箇所にカーソルがジャンプするはず。

clock2018-05-19

Xorg環境でディスプレイの解像度ではなく表示倍率を変える--scale

Before
before

After
after

問題

 上記 'Before' のように、 解像度の低いディスプレイでvivaldiのサイドタブを使っていると、 ページの表示に使える領域が非常に狭くなる。

もちろん解像度が低いので仕方ないのだけど、 同じディスプレイをWindows10またはmacOS HighSierraにつなぐと、 なんと見た目上は使える領域を広くしてくれる (表示倍率を自動調節してくれる)。

clock2018-05-16

ブログ名を変更しました(あいや☆ぱぶりっしゅぶろぐ!)

 このブログの名前を「あいや☆ぱぶりっしゅぶろぐ!」から「大銀河宇宙No.1_Haskeller」 に変更しました ⛄

 由来としては「俺が1番強いHaskellerだ!」というものではなく「皆さんが1番強いHaskellerだ!」そして「強いHaskellerどんどん生まれてくれ」という感じです。 生まれてくれ。

clock2018-04-11

Arch LinuxでEast Asian Ambiguous charが幅1で表示されることについて

 相当前から…僕のArch Linux上のTermite上のNeoVimで 「…」 という文字が幅1で表示されてしまう 問題に悩ませれている。 結局解決できなかったが……今後別の環境でまた同じシチュエーションになったときのために……まとめておく。

……

この記事中の各々のバージョン

NeoVim 0.2.2
Vim 8.0.1257
urxvt 9.22
Termite 13
tmux 2.6
clock2018-02-18

Run a program of Eff in pure contexts

In a situation, I have a program (Eff) with a STATE effect, and the program is pure.

It can be run in a pure context like below 😂

import Control.Monad.Identity
import Effect.State
import Effects

main : IO ()
main = do
  let Id (_ ** [s]) = runEnv {m=Identity} [default] $ update (+1)
  printLn s
-- {output}
-- 1

PS

I took a Pull Request, Above code can be written as below (no Identity is needed…

clock2018-02-17

IdrisでEffectモジュールなどを使おうとしたときに出るCan't find import Effect/Barの対処

問題

Main.idr

import Effect.Default

main : IO ()
main = do
  printLn $ the Int default
  printLn $ the Char default
  printLn $ the Bool default
  printLn $ the String default
  printLn $ the (List String) default
$ idris -o Main Main.idr
Can't find import Effect/Default

解決

 -peffectsを指定してあげる。

$ idris -o Main Main.idr -p effects
$ ./Main
0
'\NUL'
False
""
[]

 もちろんEffect.Barモジュール以外の時もこれを念頭に置いておくと便利。

参考ページ

clock2018-02-11

IdrisとHaskellの差異「依存型のパターンマッチが可能」

 Idrisに入門中なので、せっかくだからHaskellではできなかったけどIdrisではできること、 またその逆を定期的に挙げていきたいと思います 🐕

以下のとこには載ってないものを挙げてくつもりです!

clock2018-02-09

IdrisのREPLの設定ファイルは~/.idris/repl/init

"The file repl/init" と書いてあったものの、一瞬わからなかったのでメモ 🐕

clock2018-02-04

Haskellのdoctest (ghci) の:{..:}中のletでincorrect indentation

こんな感じのdoctestを書いていると怒られた 😭

-- >>> :{
-- >>> let result = "good"
-- >>> "good"
-- >>> :}
-- "good"
### Failure in Foo.hs:364: expression `:{
 let result = "good"
 "good"
:}'
expected: "good"
 but got:
          <interactive>:436:2: error:
              parse error (possibly incorrect indentation or mismatched brackets)

let式を使うと(letにinを付けると)正しく実行された。

-- >>> :{
-- >>> let result = "good" in
-- >>> "good"
-- >>> :}
-- "good"

ちなみにこれもだめだった 😕

-- >>> :{
-- >>> let result = "good"
-- >>> return "good"
-- >>> :}
-- "good"

マジかよ ❗ ❗


参考までに、以下は「こんな感じ」の実例。

-- >>> :{
-- >>> let result = [z|
-- >>>               (do
-- >>>                 (def! x 10)
-- >>>                 (def! y (+ 10 x))
-- >>>                 (fn* (a) (+ x y)))
-- >>>              |] in
-- >>> case result of
-- >>>      [pp|(fn* (a) (+ 10 20))|] -> "good"
-- >>>      _ -> "bad: " <> readable result
-- >>> :}
-- "good"
### Failure in src/Maru/Eval.hs:364: expression `:{ilures: 0
 let result = [z|
               (do
                 (def! x 10)
                 (def! y (+ 10 x))
                 (fn* (a) (+ x y)))
              |]
 case result of
      [pp|(fn* (a) (+ 10 20))|] -> "good"
      _ -> "bad: " <> readable result
:}'
expected: "good"
 but got:
          <interactive>:441:2: error:
              parse error (possibly incorrect indentation or mismatched brackets)
clock2018-01-27

How to use 'hasktags' in ':Denite outline'

Below lines sets to use hasktags in :Denite outline 😃

call denite#custom#var('outline', 'command', ['hasktags'])
call denite#custom#var('outline', 'options', ['--ignore-close-implementation', '--ctags', '-x'])

But it overwrites the default values, all command will be using hasktags 😭

You should add the like below lines to your .vimrc

augroup VimrcDeniteOutline
    autocmd!
    autocmd BufEnter,BufWinEnter *
        \   call denite#custom#var('outline', 'command', ['ctags'])
        \|  call denite#custom#var('outline', 'options', [])
    autocmd BufEnter,BufWinEnter *.hs
        \   call denite#custom#var('outline', 'command', ['hasktags'])
        \|  call denite#custom#var('outline', 'options', ['--ignore-close-implementation', '--ctags', '-x'])
augroup END
clock2018-01-23

1 == "x" が違法だなんて誰も言ってない!

前提

例えばJavaを例に上げると、全てのclassはObjectを継承しており、Objectがequalsメソッドを持つので 異なる型を比較(equals)できてしまいます。

class Foo {}
class Bar {}

public class Test {
    public static void main(String[] args) {
        System.out.println(new Foo().equals(new Bar()));
    }
}
// {output}
// false

これはインスタンスをアップキャストしたい際などには便利ですが、 私個人としては「ある値x,yが異なる型を持てば同じものではない(x != y)」というものを認めた方が 誤りが発生しにくいと考えています :hankey:

clock2018-01-01

数値をnewtypeした型の値として数値リテラルを使う

 Num型クラスに対してGeneralizedNewtypeDeriving拡張を使うことができるので、 例えばIntのnewtypeを作りたいけど、いちいち値コンストラクタを経るのが面倒だ という心配をする必要はない。

 貴方が想像している面倒さはこのようなものだ。

newtype Seconds = Seconds
  { unSeconds :: Int
  } deriving (Show, Eq)

incrementSeconds :: Seconds -> Seconds
incrementSeconds (Seconds x) = Seconds $ x + 1

main :: IO ()
main = do
  let seconds = Seconds 10
  print $ incrementSeconds seconds
  print . Seconds . abs . negate $ unSeconds seconds
-- {output}
-- Seconds {unSeconds = 11}
-- Seconds {unSeconds = 10}

 GeneralizedNewtypeDeriving拡張を使うことで、Seconds(+1)(-1), (*2)したり、 negateしてabsしたりすることができる。

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype Seconds = Seconds
  { unSeconds :: Int
  } deriving (Num, Show, Eq)

incrementSeconds :: Seconds -> Seconds
incrementSeconds = (+1)

main :: IO ()
main = do
  let seconds = 10
  print $ incrementSeconds seconds
  print . abs $ negate seconds
-- {output}
-- Seconds {unSeconds = 11}
-- Seconds {unSeconds = 10}
clock2017-12-31

今年のGitHubでの開発まとめ

今年に進捗したリポジトリ一覧の取り方

 リポジトリ一覧はこれで取りました!

$ for i in {1..7} ; do
    curl "https://github.com/search?l=&p=${i}&q=user%3Aaiya000+pushed%3A%3E2017-01-01+fork%3Atrue&ref=advsearch&type=Repositories&utf8=%E2%9C%93" | pup '.repo-list div div h3 a json{}' | jq -r '.[].text'
  done


GitHub WebAPIの方だとなぜか31件しか取れなかった。 それはこう。

$ curl 'https://api.github.com/users/aiya000/repos?sort=pushed' | jq -r '.[].html_url'

NeoVim上でそれを実行すると、バッファにゴミと共にこんなリストが取れるので

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 70203    0 70203    0     0  70203      0 --:--:--  0:00:01 --:--:-- 47338
aiya000/hs-kemono-friends
aiya000/aref-web.vim
aiya000/dotfiles
aiya000/aiya000.github.io
aiya000/hs-throwable-exceptions
aiya000/nico-lang
aiya000/hs-gorira
aiya000/workspace
aiya000/aho-bakaup.vim
aiya000/hs-zuramaru
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 56156    0 56156    0     0  56156      0 --:--:--  0:00:01 --:--:-- 45766
aiya000/hs-brainhack
aiya000/hs-stack-type
aiya000/hs-hucheduler
aiya000/franz-kokoro-io
aiya000/sh-hereis
aiya000/xmonad-config
aiya000/eta-doromochi
aiya000/zsh-shell-kawaii
aiya000/yi-config
aiya000/learning-Haskell
...
...

全部ヤンクして、てきとーな新規バッファにプットしてqagg3dd10jq6@aという感じにします。

(ここの6

https://github.com/search?l=&p=1&q=user%3Aaiya000+pushed%3A%3E2017-01-01+fork%3Atrue&ref=advsearch&type=Repositories&utf8=%E2%9C%93

で取れるページ数 -1 の数。 aiya000を変更してください ❗ )

そしてあとはタブ内に、ブログ記事用のmarkdownバッファを左に、 ☝ の一覧を右にして <C-b>

clock2017-12-28

TypeScript2.6のnull合体演算子も||

 これは生JavaScriptやES2017と同じであると多分思う。

TypeScriptの||は(疑似記法的に)function ||(x: boolean, y: boolean): booleanでないとは思わなかった。

clock2017-12-01

不変性を仮定した、環境をキャプチャしないクロージャ生成アルゴリズムとその問題

 この記事は言語実装 Advent Calendar 2017の、 12月1日の記事です。

ファーストバッターやっていき 💪

始まり

 皆さんは常々クロージャを作っていると思うのですが、 どのように作ってらっしゃるのでしょうか。

環境全てをキャプチャ?

包含される変数のみをキャプチャ?

ユーザ(プログラマ)の選択した変数のみをキャプチャ?

 今回僕がLisp…

clock2017-11-08

Haskell(GHC)のimport/module構文に表れるのtypeキーワードについて(ExplicitNamespaces)

 例によるGHC Haskellの中の概念の紹介記事。


 GHCのHaskellでは(おそらく主に)DataKinds拡張を用いる場合にて、以下のように import/module構文内でtypeキーワードが表れる場合がある。

Main.hs

{-# LANGUAGE ExplicitNamespaces #-}

import Test (type (==>))

main :: IO ()
main = return ()

Test.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}

module Test
  ( type (==>)
  ) where

type family (x :: Bool) ==> (y :: Bool) :: Bool where
  False ==> _     = True
  True  ==> False = False
  True  ==> True  = True

 これは厳密にはExplicitNamespaces拡張によって提供されている構文で、Main.hsとTest.hsを以下のように 改変した場合にわかりやすい。

Main.hs

{-# LANGUAGE ExplicitNamespaces #-}

import Test (type (==>), (==>))

main :: IO ()
main = print $ False ==> True

Test.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}

module Test
  ( type (==>)
  , (==>)
  ) where

type family (x :: Bool) ==> (y :: Bool) :: Bool where
  False ==> _     = True
  True  ==> False = False
  True  ==> True  = True

(==>) :: Bool -> Bool -> Bool
False ==> _     = True
True  ==> False = False
True  ==> True  = True

 つまるところ、Main.hsでtype familyの型演算子==>をimportときにtype

clock2017-11-07

Haskell(GHC)のSymbol/Natカインドの型を値に落とす方法

 Haskell(GHC)では以下のように、文字列を型として埋め込むことができます。

{-# LANGUAGE DataKinds #-}

type Str = "sugar"

main :: IO ()
main = return ()

 こうすれば値"sugar" :: Stringを取得できます。

{-# LANGUAGE DataKinds #-}

import Data.Proxy (Proxy(..))
import GHC.TypeLits (Symbol, symbolVal)

type Str = "sugar"

main :: IO ()
main = putStrLn $ symbolVal (Proxy :: Proxy Str)
-- {output}
-- sugar

Nat

 Nat(自然数カインド)も同じことができるよ。

{-# LANGUAGE DataKinds #-}

import Data.Proxy (Proxy(..))
import GHC.TypeLits (Nat, natVal)

main :: IO ()
main = print $ natVal (Proxy :: Proxy 10)
-- {output}
-- 10

参考

clock2017-11-04

VimConf2017の登壇枠に落ちたから通常参加でLTしてきた!

VimConf2017

LTで発表した内容!

  • Either Monad in Vim script
    • vital.vimのEitherモナドが高階関数を受け取る仕様上、適切な関数分割が行われやすい(行いやすい)
    • ということを意図したスライドだけど、全然盛り込めなくて口頭で補完した!

 本当はLT…

clock2017-11-03

haskell-stackにlibHSyaml-0.8.24-2wdOOQKc6Dt63OCZo8Nf1H-ghc8.2.1.soがないとか言われた

起こった問題

$ stack
stack: error while loading shared libraries: libHSyaml-0.8.24-2wdOOQKc6Dt63OCZo8Nf1H-ghc8.2.1.so: cannot open shared object file: No such file or directory

結論

 以下のコマンドで解決できる。

$ yaourt -U /var/cache/pacman/pkg/stack-1.4.0-37-x86_64.pkg.tar.xz
$ yaourt -S haskell-stack-git
# PKGBUILDの編集で、依存関係からtlibinfoとstackを消す

事の流れ

 あることのために、ArchLinuxにstatic-stackというhaskell-stack-gitと競合するパッケージを入れる必要があった。 事を終えた後にyaourt -S stackをした後に$ stackを実行してみると、以下のエラーを吐いた。

$ stack
stack: error while loading shared libraries: libHSyaml-0.8.24-2wdOOQKc6Dt63OCZo8Nf1H-ghc8.2.1.so: cannot open shared object file: No such file or directory

 つまるところ、stackコマンドほぼ全体が使えない。

 libHSyaml-0.8.24-2wdOOQKc6Dt63OCZo8Nf1H-ghc8.2.1.soはおそらくstack setupで入ったその場のghc8.2.1と結びついたライブラリだと思われる。 なので$ stack setup

clock2017-11-03

elmのインストールがnpmで失敗したからyarnでやったらできた

 公式に書いてあるLinuxのインストール方法であるこいつ、なんぞ失敗しよる。

$ sudo npm install -g elm
npm WARN deprecated node-uuid@1.4.8: Use uuid module instead
/usr/bin/elm -> /usr/lib/node_modules/elm/binwrappers/elm
/usr/bin/elm-make -> /usr/lib/node_modules/elm/binwrappers/elm-make
/usr/bin/elm-package -> /usr/lib/node_modules/elm/binwrappers/elm-package
/usr/bin/elm-reactor -> /usr/lib/node_modules/elm/binwrappers/elm-reactor
/usr/bin/elm-repl -> /usr/lib/node_modules/elm/binwrappers/elm-repl

> elm@0.18.0 install /usr/lib/node_modules/elm
> node install.js

Error extracting linux-x64.tar.gz - Error: EACCES: permission denied, mkdir '/usr/lib/node_modules/elm/Elm-Platform'
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! elm@0.18.0 install: `node install.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the elm@0.18.0 install script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2017-11-02T15_33_20_608Z-debug.log

npm もういい!もどれ!

いけ、yarn!

$ sudo yarn global add elm

こうすればうまくインストールできた。

clock2017-10-29

lens(のMonadState演算子など)で自己に言及したい時はidを使う

まとめ

 lensにて。 例えばInt[Int]のような単一の状態を持つMonadStateの文脈で、 状態自身(自己)に言及したい場合は、このようにすることで実現できる。

import Control.Lens
import Control.Monad.State.Lazy (StateT, runStateT)

main :: IO ()
main = runStateT context [0] >>= print

-- dequeue behavior
context :: StateT [Int] IO ()
context = do
  id %= (10 <|)
  id %= (|> 20)
-- {output}
-- ((),[10,0,20])
infix 4 %=
(%=) :: MonadState s m => ASetter s s a b -> (a -> b) -> m ()
(%=) :: ASetter s s a b -> (a -> b) -> StateT s m ()
(%=) :: ASetter' s a -> (a -> a) -> StateT s m ()
(%=) :: ASetter' [Int] [Int] -> ([Int] -> [Int]) -> StateT [Int] IO ()

(<|) :: a -> Seq a -> Seq a
(|>) :: Seq a -> a -> Seq a

(10 <|) :: Seq a -> Seq a
(|> 20) :: Seq a -> Seq a

type ASetter' s a = ASetter s s a a
type ASetter s t a b = (a -> Identity b) -> s -> Identity t

id :: p s (f a) -> p s (f a)
id :: (s -> f a) -> s -> f a
id :: (s -> Identity a) -> s -> Identity a
id :: ASetter' s a
id :: ASetter' [Int] [Int]

-- なので

(id %=) :: ([Int] -> [Int]) -> StateT [Int] IO ()

 ちなみにControl.Lens.Equalitysimple :: Equality' a aの実定義はid

参考

Thanks

clock2017-10-12

NonEmptyのIsListインスタンスの損なわせる型健全性

結論

 OverloadedListsNonEmptyを具体化しない方が良い。

概要

In haskell-jp slack

igrep [18:25]
OverloadedLists, 意外と怖いですね。うっかりNonEmptyに対して空リストを使ってしまうとランタイムエラーになっちゃうみたいで。。。

>>> :set -XOverloadedLists
>>> import qualified Data.List.NonEmpty as NE
>>> [] :: NonEmpty Int
*** Exception: NonEmpty.fromList: empty list
>>> [] :: [Int]
[]

理論的にはコンパイル時に fromList を実行してコンパイルエラーにできそうなもんですし、惜しい。

 OverloadedLists拡張はOverloadedStrings拡張と似た構造をしていて、 型Set, MapNonEmpty

clock2017-10-10

AWS API Gatewayのリソースを作成したらステージへのデプロイが必要

 AWSのAPI Gatewayで、受け取ったjsonパラメータをそのまま返すechoサーバをリリースに定義したのだけど、 それに対するAPI Gateway上でのテスト行うのはうまくいくのに、 下記のような手元からのcurlコマンドはうまくいかない。

$ curl \
        -H 'x-api-key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
        -d '{"dia":"ruby"}' \
        -H 'Content-Type: application/json' \
        -X POST \
        'https://xxxxxxxxxx.execute-api.yyyyyyyyyyyyyy.amazonaws.com/test/lackybeast'
{"message":"Internal server error"}

とても恐ろしい集団心理である…

  • {"dia":"ruby"}! {"dia":"ruby"}はまだか!!」
  • 「なぜ出来ない!!! 一体どうなってるんだ!!!」
  • 「エラーレスポンスが、お粗末すぎるぞォーー!!!!!」
  • 「早く…{"dia":"ruby"}をくれ…」
clock2017-10-01

僕ののHaskell開発環境を紹介する

趣旨

 僕は僕のHaskell開発環境を使っているのだけど(それはそう)、常々これはなかなか便利だと思っている。

加え、Haskellの開発環境の導入方法がよくわからないという声をとても多く聞く。

 幸い、前提となるHaskell開発ツールキットの導入については、こちらにわかりやすい記事がある。

clock2017-09-27

haskell-stackで `collect2; エラー; ldはステータス1で終了しました` が出た場合の対処

 先日yaourt -Syuuすると、haskell-stackのプロジェクトがビルドできなくなった。

$ cd {a-stack-project} && stack build
Configuring clock-0.7.2...
Building clock-0.7.2...
Preprocessing library clock-0.7.2...
/tmp/stack19865/clock-0.7.2/Clock.hsc:44:0: 警告: "hsc_alignment" が再定義されました
/tmp/stack19865/clock-0.7.2/In file included from .stack-work/dist/x86_64-linux-tinfo6-nopie/Cabal-1.24.2.0/build/System/Clock_hsc_make.c:1:0:
/home/aiya000/.stack/programs/x86_64-linux/ghc-tinfo6-nopie-8.0.2/lib/ghc-8.0.2/template-hsc.h:88:0: 備考: ここが以前の宣言がある位置です
#define hsc_alignment(t...) \

/bin/ld: .stack-work/dist/x86_64-linux-tinfo6-nopie/Cabal-1.24.2.0/build/System/Clock_hsc_make.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object。 -fPIC を付けて再コンパイルしてください。
/bin/ld: 最終リンクに失敗しました: 出力に対応するセクションがありません
collect2: エラー: ld はステータス 1 で終了しました

 Haskellができないとか意味がわからないので、直す。 これで直った。

$ yaourt -Rns libtinfo
$ yaourt -S ncurses5-compat-libs
$ rm -rf ~/.stack .stack-work

$ cd /usr/lib
$ sudo mv libncurses.so{,.bak}
$ sudo ln -s libncursesw.so.6.0 libncurses.so

原因は謎。

 後半のコマンドについてはこれ。

clock2017-09-20

Haskellを教えて、対価としてモンハンを買って貰ってきた

発端

ンゴ!?!?

アバウト

 今年のこの季節、やはり常々思うことは「SwitchのモンハンXX欲しい!」ということなので、 「Haskellを教えるので、Switchのモンハンください!」とつぶやいたら、 おキツネ美少女であるところのノエノエが「いいよ」と言ってくださったので、 某所にて密会してきました。

  • やった範囲
    • すごいH本(P.1〜P.33のうち、一部を飛ばして)
      • if, caseなどの構文はパターンマッチで代替できる場合が多いので、時間の都合上飛ばした
      • タプルもHaskellに限った概念でないので飛ばした
    • ことり、穂乃果と一緒に学ぶHaskell(入門)その1からその4(の内容)
      • 今回は代数的データ型を覚えて貰えればなと思っていた
      • これも「まずは代数的データ型を覚えて欲しい」と思って書いたものなので、内容的にちょうどよかったから引っ張り出した
clock2017-09-07

メモ: これでraspi3のイヤホンジャックから音が出た

 ラズパイのイヤホンジャックを初めて利用してみたのだけど、aplayしても音が出ない。

$ cd /opt/vc/src/hello_pi
$ sudo ./rebuild.sh
$ ./hello_audio/hello_audio.bin

とすると

failed to open vchiq instance

と言われた。

 こうするとできた。

$ echo 'SUBSYSTEM=="vchiq",GROUP="video",MODE="0660"' | sudo tee /etc/udev/rules.d/10-vchiq-permissions.rules
$ sudo gpasswd -a aiya000 video
$ sudo gpasswd -a pi video
$ sudo reboot
$ /opt/vc/src/hello_pi/hello_audio/hello_audio.bin

参考

clock2017-09-07

メモ: Rasberry PI 3 model B+をBluetoothスピーカーにした

 僕はbluetoothスピーカーが欲しかった。 でも僕の部屋には、コンセントから電源が供給されるイヤホンジャック接続のスピーカー(アナログスピーカー?) が既にあり、買うのもなんかもったいなかった。

 なのでRasberry PI 3 model B+(以下raspi3)にそれを繋いで、raspi3をbluetoothスピーカーにできないかと思って、 やってみたらできた。

clock2017-09-03

なぜ(^.)にMonoidのPrismを指定できるのか

 ここ

に書いた通り、 (^?)はあるPrismを引数に取る。

 でもPrismは必ず(^?)と一緒に使わなきゃいけないわけじゃなくって、 Monoid r => Getting r s aの形になったPrismは Lensの(^.)にも指定できる。 (例えば_Right

import Control.Lens
import Data.Monoid (Sum)

x :: Either Char (Sum Int)
x = Left 'a'

-- xはRight値ではないので、Sumの単位元であるSum 0が返る
main :: IO ()
main = print $ x ^. _Right

-- {output}
-- Sum {getSum = 0}

 実用上、Prism(^.)が(上記のように)失敗した場合は 単位元が返されるのが便利なのはわかったけど、 なんで(^.)MonoidPrismを指定できるのか?

 型を簡約して、_Right(^.)

clock2017-08-23

ネストした分岐を消す方法(タプルを使う)

 まずはこのコードを見て欲しい。

import Numeric.Extra (intToDouble)

main :: IO ()
main = do
  n <- (readLn :: IO Int)
  xs <- sequence $ replicate n (readLn :: IO Int)
  if n == 3
     then case divTotal xs of
               Just result -> putStrLn $ "succeed: " ++ show result
               Nothing     -> putStrLn "The caluculation is failed"
     else putStrLn "x("

divTotal :: [Int] -> Maybe Int
divTotal [] = Nothing
divTotal xs =
  let (x':xs') = map intToDouble xs
  in truncate <$> foldr (flip (/?)) (Just x') xs'
  where
    -- Safe (/)
    (/?) :: Maybe Double -> Double -> Maybe Double
    Nothing /? _  = Nothing
    Just 0  /? _  = Nothing
    Just x  /? y  = Just $ x / y

これは最初にユーザから整数値nの入力を受け取ってから、n個の整数値の入力を受け取った後に、 nが3であれば3つの整数値を左から右に割り算するプログラムだ。

nが3でなければエラーメッセージAを、 割り算で0除算が起こったらエラーメッセージBを、 全て正しく成功したら結果を表示する。

 しかし見て欲しい。 ifとcaseが醜くネストしている。

if n == 3
  then case divTotal xs of
            Just result -> putStrLn $ "succeed: " ++ show result
            Nothing     -> putStrLn "The caluculation is failed"
  else putStrLn "x("

clock2017-08-22

extensible-effectsの作用を拡大方向に変換する

作用とは

 この記事ではEff型の第一型引数を指します。

-- Fooは作用
Eff Foo a

拡大とは

 この記事において、作用Aが作用Bより大きいとは

type A = X :> Y :> Z
type B = Y :> Z

このようなA ⊂ Bを指し、 「拡大」は、

Eff B a -> Eff A a

のような((X :>)を補填するような)操作を指します。 (一般的になんと言うのかは知らない)

問題

 この問題についてのおおよその背景はみょんさんの記事を見た方がとてもわかりやすいと思いますが

clock2017-08-06

コミケ92 1日目金曜日 東た11bのλカ娘に記事を書いた

 8/11のC92、東た11bの『簡約!? λカ娘10』に参加します!

 λカ娘は、昨今の関数型プログラミングや定理証明系の超最新情報が集まったりしてる本っぽいです。 今回はどうやら厚めの薄い本になるみたいです。

 僕は今回のλカ娘に『矢澤にこ先輩と一緒にモナドモナド!』っていうHaskellの記事を書きました。

cover-illust

 本記事は、本書を読んでみての感想かつ紹介記事になります :D

参考

clock2017-08-03

ことり、穂乃果と一緒に学ぶHaskell(入門)その5「様々な文字列型とIsStringそしてOverloadedStrings」

Happy☆Birthday!

ことり「穂乃果ちゃん、ハッピーバースデー!」
海未「穂乃果、誕生日おめでとうございます!」

🎉

穂乃果「ことりちゃん、海未ちゃん、ありがとー!」


ことり「今日は穂乃果ちゃんの誕生日なので、海未ちゃんもお呼びしたよ♪」
海未「私はHaskell…

clock2017-07-28

typeでは型引数を省略しないと高階型クラスインスタンスにできない

class Foo (a :: * -> *)

 のように、高階型に実装されることを要求する型クラスに対して

data Bar a = Bar Int a
type Baz a b = Either (Bar a) b

のようにすると

class Foo (Baz a)

できなくなってしまって

type Baz a = Either (Bar a)

のようにするとできるという感じです。


{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}

import Control.Eff (Eff, (:>))
import Control.Eff.Exception (Fail, throwExc)
import Control.Monad.Fail (MonadFail(..))
import Data.Void (Void)
import Prelude hiding (fail)

-- `a`をつけると
type Mine a = Eff (Fail :> Void) a

-- compile error !
instance MonadFail Mine where
  fail _ = throwExc ()

main :: IO ()
main = return ()
Test.hs|13 col 10| error:
     • The type synonym ‘Mine’ should have 1 argument, but has been given none
     • In the instance declaration for ‘MonadFail Mine’

Mineの型引数aを消してみるとコンパイルが通る。

type Mine = Eff (Fail :> Void)

つまりモナドスタックのような構造のうち部分は、このような

clock2017-07-27

PatternSynonymsを用いて利用側コードを変更せずにある値構築子を削除する

 こういう型がありましたが

data SExpr = Cons SExpr SExpr -- ^ Appending list and list
           | Nil              -- ^ A representation of empty list
           | Quote SExpr      -- ^ For lazy evaluation
           | AtomInt Int      -- ^ A pattern of the atom for @Int@ (primitive)
           | AtomSymbol Text  -- ^ A pattern of the atom for @Text@ (primitive)

(Lispの)シンボルを独立した表現として定義する必要が出てきました。 そうなるとこういうの

newtype Symbol = Symbol { unSymbol :: Text }
  deriving (IsString, Show, Eq)

を定義するのが普通だと思いますが、これだとシンボルの表現がS式としてのもの、Haskell…

clock2017-07-26

Haskellのstack-build(test)の結果をGUI通知するsnowtify作ったよ

 Haskell-jpのslackの#questionで 「stack testの結果をGUIの通知デーモンに自動で表示する方法ってないですか?」と聞いたら 「残念だったな!! 無理だ! watchexecとかでガリガリやるんだな!!」(要約)と言われたので 作りました 🐕

clock2017-07-20

見た目がひどい型をTypeOperatorsで改善したらロジックと同じ見た目になった

before

myLayoutHook :: Choose (ModifiedLayout Gaps (Choose (ModifiedLayout (Decoration TabbedDecoration DefaultShrinker) (ModifiedLayout (Sublayout Simplest) TwoPane)) Grid)) Full Window
myLayoutHook = (taskbarMargin $ twoTabbedPane ||| Grid) ||| Full
  where
    taskbarMargin = gaps [(D, 40)]
    twoTabbedPane = subTabbed $ TwoPane (1/55) (1/2)

after

infixr 1 :$
type (:$) = ModifiedLayout

type (:.) x y z = x :$ (y :$ z)

infixr 2 :|||
type (:|||) = Choose

type MyLayoutHook  = (TaskbarMargin :$ TwoTabbedPane :||| Grid) :||| Full
type TaskbarMargin = Gaps
type TwoTabbedPane = SubTabbed TwoPane
type SubTabbed x   = (Decoration TabbedDecoration DefaultShrinker :. Sublayout Simplest) x

myLayoutHook :: MyLayoutHook Window
myLayoutHook = (taskbarMargin $ twoTabbedPane ||| Grid) ||| Full
  where
    taskbarMargin = gaps [(D, 40)]
    twoTabbedPane = subTabbed $ TwoPane (1/55) (1/2)

比較

type MyLayoutHook = (TaskbarMargin :$ TwoTabbedPane :||| Grid) :||| Full
{--} myLayoutHook = (taskbarMargin  $ twoTabbedPane  ||| Grid)  ||| Full

Haskellの表現力はすごい 🐕

clock2017-07-20

extensible-effectsのEffでMaybeを使う(Failを使う)

 extensible-effectsにはFailという型(作用)があるので、そちらを使うのが一番楽かと思います 🐕

newtype Exc e v = Exc e
type Fail = Exc ()
{-# LANGUAGE FlexibleContexts #-}

import Control.Eff (Member, Eff, run)
import Control.Eff.Exception(Fail, runFail, liftMaybe)

safeHeadEff :: Member Fail r => [a] -> Eff r a
safeHeadEff [] = liftMaybe Nothing
safeHeadEff (x:_) = return x


main :: IO ()
main = do
  let x = run . runFail $ safeHeadEff [1..10]
  print x

ちなみにliftMaybeMという関数をextensible-effectsにPRしました(マージされた)

clock2017-07-15

Haskell入門ハンズオンでschooさんにインタビューを受けてきた

僕の前に、Haskell 教養としての関数型プログラミングの著者さんの重城さんと、 Haskell-jpのすごい人のigrepさんがインタビューされました 🐕

メンバーすごい中に僕入ったな!?

生放送だったのか!! 緊張したー 😲

clock2017-07-04

GHCの-Wtype-defaultsを解決するにはちゃんと型付けするしかないかなあ

Test.hs

main :: IO ()
main = print 10

このコードを-Wtype-defaults付きでコンパイルすると、以下の警告が出る。 (-Wtype-defaultsはGHC-8.0.2ではデフォルトで無効)

$ stack runghc -- -Wtype-defaults Test.hs

Test.hs:2:8: warning: [-Wtype-defaults]
    • Defaulting the following constraints to type ‘Integer’
        (Show a0) arising from a use of ‘print’ at Test.hs:2:8-15
        (Num a0) arising from the literal ‘10’ at Test.hs:2:14-15
    • In the expression: print 10
      In an equation for ‘main’: main = print 10
10

10が型推論で(Num a, Show a) => aに推論されているからだ。 GHCは10を最終的に単相型で型付けする必要がある……はずなので、デフォルトのIntegerとして型付けされていて、 このままだとパフォーマンスに影響が出る。(IntegerよりIntのが速い)

型を付けて解決する。

Test.hs

main :: IO ()
main = print (10 :: Int)

他にいい解決方法ないの?

参考ページ

clock2017-07-01

MaybeTを使ってリファクタリングしたずら

 オラ、今日はLisp処理系の作成を進めてたずら。

 最初はIOの文脈で<-するために、Monadの順序の入れ替え用のこんな関数を使って連鎖してたずら。

flipUp :: Maybe (IO a) -> IO (Maybe a)

clock2017-06-27

HakyllのCompilerでemoji(:dogs:)をコンパイルする

💠 🐕 💠 (💠 🐕 💠

🐶

 僕のこのブログのposts/*.mdは、以下のようにhtmlへ、site.hsによってコンパイルされます :+1:

main :: IO ()
main = hakyll $ do
    -- 前略
    match "posts/*" $ do
    route $ setExtension "html"
    compile $ pandocCompiler
        >>= loadAndApplyTemplate "templates/post.html" postCtx
        >>= loadAndApplyTemplate "templates/default.html" postCtx
        >>= relativizeUrls
    -- 後略

pandocCompilerはhakyllによって以下のように定義されてます 😄

-- Hakyll.Web.Pandoc
pandocCompiler :: Compiler (Item String)
pandocCompiler = pandocCompilerWith defaultHakyllReaderOptions defaultHakyllWriterOptions
--pandocCompilerWith :: ReaderOptions -> WriterOptions -> Compiler (Item String)

😄のような絵文字をHakyllで使うには、pandocCompilerWithdefaultHakyllReaderOptionsreaderExtensionsText.Pandoc.Options.ExtensionExt_emojiを追加してあげます。

pandocCompilerWithEmoji :: Compiler (Item String)
pandocCompilerWithEmoji =
  let readerExtensions' = readerExtensions defaultHakyllReaderOptions
  in pandocCompilerWith
    defaultHakyllReaderOptions { readerExtensions = Set.insert Ext_emoji readerExtensions' }
    defaultHakyllWriterOptions

main :: IO ()
main = hakyll $ do
    -- 前略
    match "posts/*" $ do
    route $ setExtension "html"
    compile $ pandocCompilerWithEmoji -- !!
        >>= loadAndApplyTemplate "templates/post.html" postCtx
        >>= loadAndApplyTemplate "templates/default.html" postCtx
        >>= relativizeUrls
    -- 後略

:+1: 😃

clock2017-06-24

Haskellのtypeの中身はkind!で!(型レベルハンバーガーの型やいかに?)

 ここ4日間ぐらい、主にDataKindsTypeFamiliesを用いた型レベルハンバーガーの開発(型レベルプログラミング)を行っていた。

成果物はここにあるよ。

typeした型の中身を表示する:kind!

 Hamberger.hsではこんな感じで、型レベル関数の結果を左辺に格納している。

type BasicHamburgerC = HamburgerC Space Space Space Space

type HamburgerC1 = AddTopping BasicHamburgerC Cheese
type HamburgerC2 = AddTopping HamburgerC1 Tomato
type HamburgerC3 = AddTopping HamburgerC2 Meet
type HamburgerC4 = AddTopping HamburgerC3 Ushi
type HamburgerC5 = AddTopping HamburgerC4 Ushi

例えばHamburgerC4HamburgerC5の結果が見たいとき、 もしこれらが(Showである)値であればprint

clock2017-06-12

【結論】Textの中のStringにmap :: String -> StringするにはProfunctorが一番!

 ときどきTextにpack,unpackを介してString -> Stringしたくなるシチュエーションに出会う。 でも普通に関数合成すると、なんだか格好悪いんだよね。

{-# LANGUAGE OverloadedStrings #-}

import Data.Char (toUpper)
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.IO as TIO

-- Data.TextのtoUpperを使えとか言っちゃだめ! そしたら別の適切な例を教えて!
upper :: String -> String
upper = map toUpper

x :: Text
x = "nico"

main :: IO ()
main = do
  let niconico = T.pack . upper $ T.unpack x -- 格好悪い
  TIO.putStrLn niconico

 Profunctordimapを使う。 (->)Profunctorを使えばdomainとcodomainの変更を一気にできるので、 Text -> StringString -> StringString -> Textを格好良くできる!(まあ中身は👆と全くおんなじなんだけどでも見栄えいい)

 これはその型と同型の型への操作に一般化できますので、newtype

clock2017-06-10

Firefoxのflash動画再生で音が出なかったから直った

 Arch Linux x86-64です。

pulseaudioが入ってる状態。

$ yaourt -S pulseaudio-alsa

はい。

clock2017-06-09

vital.vim開発者会言ぎに行ってきた

 どーも、vital.vim開発者会議に行ってきました。

 これにはvital.vimのコア開発者がなんか面倒なIssueとかを、実地に集まることによる密なコミュニケーションにより 消費していくというアレです。

 僕もこの前Data.EitherをPull Requestして vital.vimミッター入りとvim-jp…

clock2017-06-08

Hakyllの各記事ページのタグにリンクを付けた

成果物

何?

 👆にあると思うんですが、Tagsにリンクがつくようになりました。

before

after

 HakyllとHakyllのドキュメントがわからないので、Compiler, Item, Identifier, Contextについてctags…

clock2017-06-05

Linuxとxfce4でSSH鍵のパスフレーズ入力を永続的に省略する

想定

 ssh接続先の認証にはパスフレーズではなく鍵認証が設定されていて、その鍵にパスフレーズを設定している。
ssh接続時にその鍵のパスフレーズを入力することなく接続できるようにする。

xfce4を使用している。

結論

 gnome-keyringとseahorseを使用する。
gnome-keyring 全てはこちらに書いてある。

clock2017-05-30

tasty-discoverを使ってみた

参考ページ

何それ?

 Haskellプロジェクトのtest-suiteのmain-isなるソースを書かずに、test-suite…

clock2017-05-27

にこ、希と一緒に学ぶHaskell(番外)「型クラスの定義と実装(Extra)」

にこ、希と一緒に学ぶHaskell(番外)について

希 & にこ「どうもこんにちは〜」

にこ「毎度おなじみ、Haskellerとして名の通ってる、みんなのニコニーです!」
希「東條希やで〜」

にこ「あなたのハートににこにこにー♪」

clock2017-05-12

ことり、穂乃果と一緒に学ぶHaskell(入門)その3「代数的データ型の定義2」

前回

ことり「穂乃果ちゃん、関数の定義方法は授業では習った?」
穂乃果「い…いちおう……。 えーと、こういうのだっけ」

add1 :: Int -> Int
add1 x = x + 1

ことり「:: Int -> Intっていうのは、add1っていう関数にInt -> Intっていう型を付けているんだ Java…

clock2017-05-11

ことり、穂乃果と一緒に学ぶHaskell(入門)その2「関数とデータ型」

前回

ことり「次は、Memberデータ型をmainで表示してみるよ」
ことり「これはこう書けるよ」

data Member = Member String Int
  deriving (Show)

ことり「deriving (Show)って行を追加したよ」
ことり「こういう単純なパターンを実装したい時には、derivingっていうのを使うよ!

clock2017-05-06

ことり、穂乃果と一緒に学ぶHaskell(入門)その1「代数的データ型の定義」

前置き(海未ちゃん)

海未「この度は『ことり、穂乃果と一緒に学ぶHaskell(入門)』にお越しいただき、ありがとうございます」
海未「本企画はこちらの偉大なブログ様に触発されたものです。 是非こちらもご覧ください」

海未「キャラ崩壊を含む可能性があります。 ご容赦くださいますよう」

clock2017-04-22

とれたてHaskellまるごと1日分の入ったHaskellプロジェクトがこれです

 今日はこんなのを作りました。

例により、@blac_k_ey@yassu0320と謎の店に集まり、作業しました。


 これは、実行されると予め設定ファイルに書いておいた、曜日ごとの予定を表示してくれる、簡単なCLIアプリです。
例えば、.zshrc.zshenv的なものに、これを実行させるように書いておけば、一日の最初にシェルを開いたときに、予定を教えてくれます。

clock2017-04-12

haskell-stackでcan't load .so/.DLL for 〜/libncurses.soが出た場合の対処

対処

 ワークアラウンドを施します。

$ cd /usr/lib
$ sudo cp libncurses.so{,.bak}
$ sudo ln -s libncursesw.so.6.0 libncurses.so

参考

clock2017-04-09

技術書展2に行ってきた! めっちゃ楽しかった!

😂(照れ)

scene

技術書展2 参加記事



 今日、秋葉原で行われた 技術書展2に行ってきました!
私的には初めての同人誌即売会です。

techbookfest2-image

 秋葉原は結構うちから遠いのですが、朝早く起きることができたので、10:50に入り口へ到着することができました。

 開場前、待機列の僕らの前には1レーン分の人々がいましたが、2レーン目の前の方に並べたのでかなりいい方でしょう!
友人に「Haskell…

clock2017-04-08

単相化された存在型のランク2での謎

ランク2多相をランク1多相として使おうとしたときの問題?

 これはできるのですが

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE Rank2Types #-}

import Control.Monad (void)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.String (IsString, fromString)
import System.Environment (getEnv)


type FilePath' = forall s. IsString s => s


inHomeDir :: MonadIO m => (FilePath' -> m a) -> m a
inHomeDir f = do
  homeDir <- liftIO $ getEnv "HOME"
  f $ fromString homeDir


printFooAppDir :: IO ()
printFooAppDir = inHomeDir body
  where  -- 型を明示するために関数分割してます
    body :: FilePath -> IO ()
    body homeDir = putStrLn $ homeDir ++ "/.config/foo"


main :: IO ()
main = printFooAppDir

これは

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE Rank2Types #-}

import Control.Monad (void)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Monoid ((<>))
import Data.String (IsString, fromString)
import Data.Text (Text)
import Data.Typeable (Typeable)
import Data.Typeable (cast)
import System.Environment (getEnv)
import qualified Data.Text.IO as TIO


type FilePath' = forall s. IsString s => s

newtype BakaFilePath = BakaFilePath { unBakaFilePath :: Text }
  deriving (IsString, Monoid, Typeable)

putBakaLn :: BakaFilePath -> IO ()
putBakaLn = TIO.putStrLn . unBakaFilePath


inHomeDir :: MonadIO m => (FilePath' -> m a) -> m a
inHomeDir f = do
  homeDir <- liftIO $ getEnv "HOME"
  f $ fromString homeDir


printFooAppDir :: IO ()
printFooAppDir = id' . inHomeDir $ body . cast'
  where
    -- MonadIO mからMonadIO nへの単相的な変換。 IO ()を期待する
    id' :: IO () -> IO ()
    id' = id

    cast' :: FilePath -> Maybe BakaFilePath
    cast' = cast

    body :: Maybe BakaFilePath -> IO ()
    body Nothing = error "baka"
    body (Just bakaHomeDir) = putBakaLn $ bakaHomeDir <> "/.config/foo"


main :: IO ()
main = printFooAppDir

こうなり

Test.hs|34 col 24| error:
     • Couldn't match type ‘FilePath’ with ‘FilePath'’
       Expected type: (FilePath -> IO ()) -> IO ()
         Actual type: (FilePath' -> IO ()) -> IO ()
     • In the second argument of ‘(.)’, namely ‘inHomeDir’
       In the expression: id' . inHomeDir
       In the expression: id' . inHomeDir $ body . cast'

コンパイルに失敗します。
(bakaHomeDir :: BakaFilePath) <> ("/.config/foo" :: BakaFilePath)としてもだめ。

回答

 inHomeDirを単相化すればいいみたい。

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE Rank2Types #-}

import Control.Monad (void)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Monoid ((<>))
import Data.String (IsString, fromString)
import Data.Text (Text)
import Data.Typeable (Typeable)
import Data.Typeable (cast)
import System.Environment (getEnv)
import qualified Data.Text.IO as TIO


type FilePath' = forall s. IsString s => s

newtype BakaFilePath = BakaFilePath { unBakaFilePath :: Text }
  deriving (IsString, Monoid, Typeable)

putBakaLn :: BakaFilePath -> IO ()
putBakaLn = TIO.putStrLn . unBakaFilePath


inHomeDir :: MonadIO m => (FilePath' -> m a) -> m a
inHomeDir f = do
  homeDir <- liftIO $ getEnv "HOME"
  f $ fromString homeDir


printFooAppDir :: IO ()
printFooAppDir = id' . (inHomeDir :: (FilePath -> IO ()) -> IO ()) $ body . cast'
  where
    id' :: IO () -> IO ()
    id' = id

    cast' :: FilePath -> Maybe BakaFilePath
    cast' = cast

    body :: Maybe BakaFilePath -> IO ()
    body Nothing = error "baka"
    body (Just bakaHomeDir) = putBakaLn $ bakaHomeDir <> "/.config/foo"


main :: IO ()
main = printFooAppDir

これcastに失敗してNothingしてerror呼ぶけど、問題ないね!
コンパイル通れば、あとはどうとでもできる。

clock2017-03-02

DOOGEE X5 Max Proがコスパ最強で最高の端末

 半年前くらいからDOOGEE X5 Max Proを使っているのですが、ようやくおすすめできる環境になったのでおすすめします。
↓↓↓

↑↑↑

全て合わせて、本日時点では14,578円。   低価格マニアにとって最高の逸品になってます。

DOOGEE X5 Max Proの何がいいの?

 コスパが最高。 iPhone6 Plusから乗り換えDOOGEE X5 Max Pro…

clock2017-02-18

bindkey -vしてた人向けのauto-fu.zsh導入方法

 このPRで色々教えてもらったので書いときます。

 まず今まで使ってたキーバインド名、viinsafuvicmdafu-vicmdという名前に割当たります。
afuは補完機能付きviinsafu-vicmdafuvicmd(の代わり)を行き来するためのものです。

auto-fu.zshの導入前後の、zsh設定の具体的な変更内容

Before

# Use viins
bindkey -v

# Vim nize
bindkey -M vicmd '_'  vi-first-non-blank
bindkey -M vicmd 'g_' vi-end-of-line

# Emacs nize
bindkey -M viins '^n' down-history
bindkey -M viins '^p' up-history
bindkey -M viins '^a' beginning-of-line
bindkey -M viins '^e' end-of-line
bindkey -M viins '^b' backward-char
bindkey -M viins '^f' forward-char
bindkey -M viins '^k' kill-line
bindkey -M viins '^u' backward-kill-line
bindkey -M viins '^d' delete-char

After

source /path/to/auto-fu.zsh

# Use afu-vicmd
zle -N zle-keymap-select auto-fu-zle-keymap-select

# Vim nize
bindkey -M afu-vicmd '_'  vi-first-non-blank
bindkey -M afu-vicmd 'g_' vi-end-of-line
bindkey -M afu '^['   afu+vi-cmd-mode
bindkey -M afu '^X^V' afu+vi-cmd-mode  # Escでafu-vicmdに行く

# Emacs nize insert mode
bindkey -M afu '^n' down-history
bindkey -M afu '^p' up-history
bindkey -M afu '^a' beginning-of-line
bindkey -M afu '^e' end-of-line
bindkey -M afu '^b' backward-char
bindkey -M afu '^f' forward-char
bindkey -M afu '^k' kill-line
bindkey -M afu '^u' backward-kill-line
bindkey -M afu '^d' delete-char

実際にviinsafuvicmdafu-vicmdが割り当たってるのがわかるかと思います。

最後に注意

 zle -N zle-keymap-select auto-fu-zle-keymap-selectは既存のzle-keymap-select

clock2017-02-11

Text(ByteString)をnewtypeした型でもOverloadedStringsできるよ。

GeneralizedNewtypeDeriving拡張を使う。

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}

import Data.String (IsString)
import Data.Text (Text)

newtype A = A Text deriving (IsString, Show)

a :: A
a = "ahoge"  -- 文字列リテラル of A

main :: IO ()
main = print a
clock2017-02-03

yiテキストエディタのインストール方法

 haskell-stackはインストールされているものとする 🐕

$ git clone https://github.com/yi-editor/yi yi
$ cd yi/yi
$ LANG=C stack setup
$ LANG=C stack build
$ LANG=C stack install

$LANGを外すと、cairoパッケージあたり? でGtk2Hs関連のエラーが出る。

--  While building custom Setup.hs for package cairo-0.13.3.1 using:
      /tmp/stack16474/cairo-0.13.3.1/.stack-work/dist/x86_64-linux-tinfo6-nopie/Cabal-1.24.2.0/setup/setup-to-file"
    Process exited with code: ExitFailure 1
    Logs have been written to: /home/aiya000/Repository/yi...

    [1 of 2] Compiling Main             ( ...
    [2 of 2] Compiling StackSetupShim   ( ...
    Linking /tmp/stack16474/cairo-0.13.3.1/.stack-work/dist/x86_64-linux-tinfo6-nopie/Cabal-1.24.2.0/setup
    Configuring cairo-0.13.3.1...
    Building cairo-0.13.3.1...
    Preprocessing library cairo-0.13.3.1...
    setup: Error in C header file.

    ./cairo-gtk2hs.h:1: (column 0) [FATAL]
      >>> Lexical error!
      The character '#' does not fit here.


--  While building custom Setup.hs for package glib-0.13.4.1 using:
      /tmp/stack16474/glib-0.13.4.1/.stack-work/dist/x86_64-linux-tinfo6-nopie/Cabal-1.24.2.0/setup/setup-to-file"
    Process exited with code: ExitFailure 1
    Logs have been written to: /home/aiya000/Repository/yi...

    [1 of 2] Compiling Main             ( ...
    [2 of 2] Compiling StackSetupShim   ( ...
    Linking /tmp/stack16474/glib-0.13.4.1/.stack-work/dist/x86_64-linux-tinfo6-nopie/Cabal-1.24.2.0/setup/...
    Configuring glib-0.13.4.1...
    Building glib-0.13.4.1...
    Preprocessing library glib-0.13.4.1...
    setup: Error in C header file.

    /usr/include/glib-2.0/glib-object.h:1: (column 0) [FATAL]
      >>> Lexical error!
      The character '#' does not fit here.

(今回はyi-editor/yiyi-config/yi-originディレクトリにクローンしてある)

 手元の都合に応じてSTACK_YAML=lts-6.yamlなどを指定してあげると、対応したstackageのltsバージョンでビルドできる。 指定しなければyi/yi/stack.yamlの内容でビルドされる。

$ ls yi/yi/lts-*
yi/yi/lts-6.yaml  yi/yi/lts-7.yaml
clock2017-01-31

Data.CharのisAlphaはマルチバイト文字を正しく扱えない

 isAlphaNumも同様。
まじ注意。

Prelude> import Data.Char
Prelude Data.Char> isAlpha 'あ'
True
Prelude Data.Char> isAlphaNum 'あ'
True

これを定義しておけばいいんだけど、他にどっかData.Text以下あたりでexportしてないかなー。

isAlpha' :: Char -> Bool
isAlpha' c = c `elem` ['A'..'Z']
          || c `elem` ['a'..'z']

isAlphaNum' :: Char -> Bool
isAlphaNum' c = c `elem` ['A'..'Z']
             || c `elem` ['a'..'z']
             || c `elem` ['0'..'9']
clock2017-01-26

xf86-input-wacomをインストールしたら依存関係ダメだったから直した

xf86-input-wacomをインストールしようとしたら、xorg-serverとの依存関係でダメだった。

$ yaourt -S xf86-input-wacom
依存関係を解決しています...
衝突するパッケージがないか確認しています...
:: xf86-input-wacom と xorg-server が衝突しています。xorg-server を削除しますか? [y/N] n
エラー: 解決できないパッケージの衝突が検出されました
エラー: 処理の準備に失敗しました (衝突する依存関係)
:: xf86-input-wacom と xorg-server が衝突しています (xorg-server<1.19)

xorg-serverをアップデートしたら直った。

$ yaourt -S xorg-server
依存関係を解決しています...
衝突するパッケージがないか確認しています...
:: xorg-server と xf86-input-evdev が衝突しています (X-ABI-XINPUT_VERSION)。xf86-input-evdev を削除しますか? [y/N] y

パッケージ (4) libxfont2-2.0.1-1  xf86-input-evdev-2.10.3-1 [削除]  xf86-input-libinput-0.23.0-1  xorg-server-1.19.1-1
$ yaourt -S xf86-input-wacom
依存関係を解決しています...
衝突するパッケージがないか確認しています...

パッケージ (1) xf86-input-wacom-0.34.0-1
clock2017-01-20

2016年につくったやつ一覧 :D

 りんだんさんのやつのパクリ記事です。

github contributions
※さっき撮りました

Index

2016年につくったやつ一覧

GitHub Advanced Search

Vimプラグイン

  • aref-web.vim
    • Vimから非同期的にウェブページを開きに行くやつ
    • Web辞書とかを引く用。 例えばWeblio辞書とか、HoogleとかStackageとか
    • この一覧の中でも、特に力を入れているものの一つ
    • 皆、使って
    • どんな感じかは、GitHubのREADME.mdを見てもらえればわかると思う
  • adrone-hs.vim
    • HaskellでVimプラグインを書くという試み
    • WIP
    • adrone.vimというVim用の、 TweetVim風に日記を書くためのプラグイン …を色々改良するために作った
      • adrone.vimはすっごいVim plugin作りたての頃に作ったものなので、色々アレ。 まあ使う分には問題ないし、実際私的にすごく使ってる。
clock2016-12-30

矢澤にこ言語が完成(※)しました

Haskell製にこ言語

合宿所の近くの海

謎の集団で合宿に行ってきた

 某所に技術関連の集まりで技術合宿をしてきました。
各位、目的は各々で決めていく感じの3日連続もくもく会という感じです。

  • 僕の主観内で観測された各位の動き
    • DeepLearning
      • Tensorflow
    • VR
      • Unity + Android
    • ラズパイ電子工作
      • Lチカ
    • AngularJS1の勉強
    • Javaの勉強
    • CentOSデスクトップ環境構築
      • Archデスクトップ環境構築だったはずが、いつの間にかCentOSに変わっていた
    • LinuQuestという謎の企画について
clock2016-12-25

HHKB Lite2 JP配列のクリスマスプレゼントを貰った

 とても嬉しい!
今までは一般的な配列のUSBキーボードや、ノートPC据え付きのキーボードを使っていた。

 それらではIMEの有効化/無効化をCapsLockキーで行っていたので、巷では約立たずと言われているCapsLockキーも 僕にとってはかなり有効なものだった。
左手小指でキーを押下するだけでIMEを有効無効にできるからね、正直よく言われる「Vimと日本語はIME…

clock2016-12-21

ラブライブ! スクフェスACをやってきた! with 穂乃果ちゃん

 ラブライブ! スクールアイドルフェスティバル 〜after school ACTIVITY〜を初体験すべく昨日、 いい感じの場所に行ってきました!

スクフェスAC

 まず僕はそもそもゲーセンにあまり行かない人種なので、最初、行動に迷いました。
とりあえずスクフェスACの筐体に行ってみよう……と思って筐体の前のイスに座ったら、… なんとスクフェスAC待機列というのがあり、気づかずになんかズル込みしてしまうところでした!!

clock2016-12-19

meguro.vimに参加してきました

 だんだんと周りに「Haskell大好き人間」として把握され始めていて、まんざらでもない あいやです。
それに見合った知識を付けねばならないね :)


Meguro.vim #1 - connpass


やったこと

 まず、この記事を書きました :)


 その後、もう既にいくつかの修正依頼に対して3週間くらい費やしている このPRをやり切るべく、めっちゃやってましたが Haskell…

clock2016-12-17

使いたいVimプラグインがNeoVimで対応してない? NeoVimは環境、VimはVMだよ?

 ドーモ、最近NeoVimを使い始めたyiコントリビューターのVimmerのあいやです。
この記事はVim Advent Calendar 2016 - 17日目の記事ではありません
だってもう、既に枠が埋まってたんだもん。

NeoVimで動かないVimプラグインを動かす

僕が開発してるaref-web.vimっていうのがあるんですが


clock2016-12-13

aref-web.vimの紹介 - Vimアドベントカレンダー2016 - 14日目

 ドーモ、この前「HaskellでTwitterのbot作ってるんですよー」って言ったら
「ああ、このアカウントですよね!」って言われて、僕のメインアカウントを指されたあいやです :D

aref-web.vimの紹介をします!
インストールしてね!

aref-web.vimとは

 weblio翻訳やHaskellのHoogleなど… いわゆるWeb辞書をVim上から扱うプラグインです。
Web…

clock2016-12-09

gitでcommitを1つに統合すべき場合 及び 1つのcommitを分解すべき場合 - プロ生アドベントカレンダー2016 - 9日目

 なんか勢いでブログ記事を書いたところ、丁度今日のプロ生アドベントカレンダーが空いてたので登録する。
本記事はQiita版プロ生アドベントカレンダー 9日目の記事です。
昨日の記事はUnityからマウスカーソルを操作するでした :D
えっ、なにこれ、プロ生ちゃんがこっちのマウスカーソルを制御してるの? すごい。

宣伝

マスコットアプリ文化祭2016では

僕の作品の画像

こういうものを登録しました :D

clock2016-12-02

Yiが定義する型の紹介 - Haskell Advent Calendar 2016 - 4日目

 ドーモ、fix関数の簡約が「いい感じにやる」といった理解しかできないあいやです。
この記事はHaskell Advent Calendar 2016 4日目の記事です。

私何もあげられるものないから、yiの型書くよ!

 この記事ではYi型とyiエディタの区別をするために、yiエディタのことは「yi」と呼称します :)

Yi…

clock2016-11-23

PullRequestをしよう! - プロ生アドベントカレンダー2016 - 1日目

この記事はQiitaプロ生アドベントカレンダー2016、一日目の記事です! :)

 プログラマ諸君、PRをしましょう!(唐突)

 Qiitaプロ生アドベントカレンダーはIT関連の記事なら何でもOKということで、珍しくGenericな記事を書いてみます。
ちなみにマスコットアプリ文化祭では

僕の作品の画像

こういうものを登録しました :D

 僕は…Unityの物理演算、VR、スマホアプリ作成やコミPo…

clock2016-11-15

日本語環境のLANGでstack haddockができないやつの解決

 haskell-stackを使ってstack haddockを実行すると、Foo.hs: invalid byte sequenceみたいなエラーが出ることがある。

解決方法

LANGをen_US.UTF-8にする。

$ LANG=en_US.UTF-8 stack haddock

参考ページ

"invalid argument" error with stack haddock and Nixpkgs #2452

clock2016-11-07

VimConf2016にLT枠で参加してきたよ! (通信容量多めなのでケータイ回線等の閲覧注意)


VimConf 2016 は無事に終了しました。また来年お会いしましょう :)


この記事は、多くのツイッターへのリンク及び画像の取得を含みます
ケータイ回線だと多分いっぱい容量を食べていくので、どうかご注意を!


 ドーモ、このアイコン
profile-icon
でこのLT

をしてきた、あいやです!

 この参加記事はあいやのVimConf2016を淡々と書くものであり、過度な期待はしないでください。

clock2016-11-04

cmdargsはargsと同時にhelpを設定するとシぬ

clOptions :: CommandLineOptions
clOptions = CommandLineOptions
  { frontend    = "vty"   &= help "The frontend to use"
  , startOnLine = Nothing &= help "Open the (last) file on line NUM"
  , files       = []      &= help "FILES..." &= args  -- ここ
  }

デフォルトの引数をfilesで受けとりたくば、helpを消せ。
さもなくば我々をcmdargsがコロす。

clOptions :: CommandLineOptions
clOptions = CommandLineOptions
  { frontend    = "vty"   &= help "The frontend to use"
  , startOnLine = Nothing &= help "Open the (last) file on line NUM"
  , files       = []      &= args  -- ここ
  }

忘れるなよ。

clock2016-10-29

Yokohama.vim#8に行ってきた

まともな参加記事は以下!

出来事

 最初の出来事といえば、エレベーターの中で出会ったderisさんをyoshitiaさんと言ってしまい、間違えた。
ごめんなさい!!?

自己組織化ゲーム(Vim)

 参加者の緊張やシャイさを考慮した粋な枠。
自己組織化ゲーム(Vim)というのは、以下のルールのゲーム。

  1. 参加者は各々の二人組になる
  2. 組のうち1人は、もう1人から指示を受けるだけのアレになる
  3. 組のうちもう1人は
    • 発声により、指示を受けるアレの人に以下の指示を与えることができる
      • H - アレの人を一歩分、左に移動させる
      • J - アレの人を一歩分、下?に移動させる
      • K - アレの人を一歩分、上?に移動させる
      • L - アレの人を一歩分、左に移動させる
    • 指示を受けるアレの人が進んだ歩数を数える
clock2016-10-14

君の名は。を観てきた(ネタバレはありません)

 映画「君の名は。」を観てきました!
観て、劇場でパンフとサントラを買ってきました! :D

 絵は綺麗だし、人物は可愛いし、話はいいし…最高な…。
三葉ちゃん絶対いろんな髪型似合う可愛いし、瀧くんには是非、女装してもらいたい。


 ブログの背景に紅いのを追加しました。
毎度、僕の絵はアレなんですが、これが何かわかってしまった人。

clock2016-10-02

今週Archに入れたパッケージ

Official, AUR混合です。

  • Scala環境
    • sbt
    • scala
      • scala, scalacコマンド単体
      • sbtと違ってシステムグローバルにインストールされる
    • scala-docs
  • typesafe-activator
  • 開発用

    • ctags
    • intellij-idea-community-edition
      • いわゆるIntelliJ
    • mono
      • 最近やっと.NET Coreがマジ対応したのですが、こちらも入れておく
    • python2-pip
      • これの依存している pyserialを入れるために
    • mikutter
      • いつもの
  • Arch環境

    • pulseaudio
    • laptop-mode-tools
    • xvidcap
      • gifを撮る用
    • flashplugin
      • ニコッ☆
    • xscreensaver
      • これでロック画面を導入した
      • xscreensaver-command -lock
    • wine
    • bluez
      • bluetooth環境
      • 入れたけど謎エラーで使えてない
    • bluez-utils
    • pulseaudio-bluetooth
    • steam-libs
      • steamを使えるようにするやつ
      • りひにー様に教えてもらった
clock2016-10-01

Haskellのmplusってもしかしてすごい便利じゃない?

束縛(<-)とcaseでインデントが多くネストしてしまいそうな式でも、少ないインデントで済ませられる。

Maybeで使う

import Control.Monad (liftM2)
import Control.Monad (MonadPlus(..))

main :: IO ()
main = do
  print $ Nothing  `mplus` return 1
  print $ return 1 `mplus` (return 2 :: Maybe Int)
  print $ Nothing  `mplus` (Nothing  :: Maybe Int)
  let x = return (return 1) :: IO (Maybe Int)
  let y = return Nothing    :: IO (Maybe Int)
  print =<< liftM2 mplus x y
Just 1
Just 1
Nothing
Just 1

(IO Maybe)で使う

fooDBFile :: (MonadIO m, MonadThrow m) => m (Maybe FilePath)
fooDBFile = do
  let maybeDir = liftM2 mplus (getEnv "XDG_DATA_DIR") (getEnv "HOME")
  case maybeDir of
    dir     -> dir ++ "/foo.db"
    Nothing -> error

ベンリ。

clock2016-09-29

xmonadが最高のウィンドウマネージャである理由

この記事は僕がxmonadの利点を思いつくたびに更新されていきます。
いくらでも思いついちゃうからね :D

xmonadとは

こんなん

一般的利点

  • タイル型である
  • マウスめっちゃ使わなくなる
  • 設定がチューリング完全 (設定次第でなんでもできる)
    • 例えばworkspaceの切り替えをSuper + [1-9]に割り当てるなどのような規則のある設定とかを、 愚直に書かずにプログラミングによって生成、設定できる
  • xmonad-contribというxmonadのアドオンがあって 誰でもxmonadをカスタマイズできるようになっている
    • xmonad標準にはないレイアウトとかツールが有志によって提供されている
clock2016-09-26

聲の形を観てきた(ネタバレはありません)

 昨日、映画 聲の形を観てきました。
観て、劇場でパンフとピンズバッチとノートを買って、 近くにAnimateがあったのでサントラを買ってきました。

硝子ちゃんがやわらかくて可愛かったです。

その後、pixivで聲の形タグを回ったりしました。

clock2016-09-23

HaskellにはifMという関数がある

最近Haskellコードのcaseを多用するようになってたので、インデントレベルが3以上になってしまいそうで悩んでた X(

こんなん

main :: IO ()
main = do
    x <- getFooMaybe  -- indent 1
    case x of
        Nothing -> ...
        Just x' -> do  -- indent 2
            ...  -- indent 3
            ...

インデントレベル3はギリギリとして、4以上になるとコードの醜さが顕著に…ね?

main :: IO ()
main = do
    x <- getFooMaybe
    case x of
        Nothing -> ...
        Just x' -> do
            y <- getBarEither
            case y of
                Left  e -> fail e
                Right a -> do
                    putStrLn "succeed"
                    print a

ifM

強い。

before

import Control.Monad.Extra (ifM)

-- Read Twitter OAuth from serialized data file
readOAuth :: (MonadThrow m, MonadIO m) => m OAuth
readOAuth = do
maybeOAuth <- liftIO $ fmap read <$> getEnv "GORIRA_OAUTH"
case maybeOAuth of
    Just oauth -> return oauth
    Nothing    -> do
        x <- liftIO $ doesFileExist "resource/twitter_oauth"
        if x then liftIO $ read <$> readFile "resource/twitter_oauth"
             else throwM $ IOException' "'resource/twitter_oauth' is not exists"

after

import Control.Monad.Extra (ifM)

-- Read Twitter OAuth from serialized data file
readOAuth :: (MonadThrow m, MonadIO m) => m OAuth
readOAuth = do
maybeOAuth <- liftIO $ fmap read <$> getEnv "GORIRA_OAUTH"
case maybeOAuth of
    Just oauth -> return oauth
    Nothing    -> ifM (liftIO $ doesFileExist "resource/twitter_oauth")
                    (liftIO $ read <$> readFile "resource/twitter_oauth")
                    (throwM $ IOException' "'resource/twitter_oauth' is not exists")
clock2016-09-12

今週Archに入れたパッケージ

 今週以外のも含まれてるかも。
今週はxmonad, xmobar日和です。

xmobar preview

  • 公式パッケージ

    • alsa-utils
    • dmenu
      • xmobarでベンリに動作するAPPランチャ
    • dropbox
      • dropboxとHDDのフォルダを同期するやつ
    • nitrogen
      • xmonad使ってる時に.xinitrcでwallpaper設定するやつ
    • openssh
    • pm-utils
      • ハイバーネートできるやつ
    • rxvt-unicode
      • urxvtという軽量なターミナル
    • vlc
      • いい感じのGUIメディア再生するやつ
clock2016-09-07

xfce4でWindowsのWin+\[1-9\]キーみたいな切り替えを実現する

kore

 Windows環境では、複数のGUIアプリを立ち上げている際にWinキー + 1~9キーでウィンドウを切り替えることができる。
便利なので僕のArchLinux + xfce4環境にも導入する。

インストール

 AURからdockbarxxfce4-dockbarx-pluginを入れる。

$ yaourt -S dockbarx xfce4-dockbarx-plugin

設定

 後はxfce4のパネルを右クリックしてDockbarXを追加して、自由にdockbarxの設定をしたりなどする。

clock2016-09-06

いい加減ArchLinuxでのhibernate環境の構築についてメモっとく

 以前kernelバックエンドを使わないsuspend on disk(hibernate, s2disk)の環境を作った時も (面白いけど)苦労したのにメモってなかったのでまた(面白いけど)苦労した。
ので作業を思い出して、メモしておく。

構成

 構成はuswsusp + pm-utilsにする。
uswsusp…

clock2016-09-06

ArchLinuxでlinux-ltsカーネルを使っている時のmkinitcpio

ArchLinuxでlinux-ltsカーネルを使っている時のmkinitcpioは-p linux-ltsを指定する

clock2016-09-03

僕がArchLinuxインストール直後にインストールしたパッケージ全集

公式リポジトリより

  • 基本

    • tmux
    • git
    • rsync
    • pkgfile
    • mlocate
      • updatedb + locate コマンド
    • gvim
    • w3m
    • fzf
  • カーネル/ブートローダ 周り

    • grub
    • os-prober
      • grub-mkconfig時にWindows(とか?)を検知するために入れる
    • linux-lts
      • 今回そもそも最新linuxカーネルによって環境が死んだことによるOSのクリーンインストールなので、 カーネルをlinuxパッケージじゃなくてlinux-ltsでalternateする
      • linuxの代わりにlinux-ltsを使うのは、linuxパッケージを削除した後にgrub-mkconfigすればいい
clock2016-08-22

ベッドは眠い

ベッドは眠い

 今までベッドから起きると丁度前にデスクがあって、ベッドをイスにするような構成にしてたのですが すごく進捗が出なかったので、デスクをベッドから話してみたら進捗が少し出るようになりました。

clock2016-08-13

ラズパイのためのパーティション分割

ラズパイのためのパーティション分割

 ラズパイ3 Type Bを買ったので、ラズパイのブート領域であるmicroSDへの過度な書き込みアクセスを避けるべく 32GBのUSBメモリに5つのパーティションを分割して移す。

  • ※多分microSDは書き込みアクセスに対する寿命がHDDやUSBメモリ(SSD)よりも短い
    • あんまり詳しくない
  • このUSBメモリ、USB3.0規格だけど、ラズパイに3.0ポートはない
  • microSDは8GB
clock2016-08-09

ラズパイスワップマシマシノンデバイスで

ラズパイスワップマシマシノンデバイスで

 なぜかラズパイのデフォルト仮想メモリサイズが100Mだったので足りない。
物理メモリが1Gなようなので、仮想メモリも1G~2Gが順当だろうて。

参考ページ

clock2016-08-09

Node.jsでprettyprintする

Node.jsでprettyprintする

 これ使う。
prettyprint

現在、README.mdには

var prettyprint = require('prettyprint').prettyprint;
prettyprint.prettyprint(obj);

しろと書いてあるけど、実際は

const prettyprint = require('prettyprint').prettyprint;
prettyprint(obj);

で動作した。
注意。

clock2016-08-06

NOeSISカフェに行ってきた

NOeSISカフェに行ってきた

 念願のNOeSISカフェに行ってきました!!

パセラボ コラボレーション: 人気ライトノベル携帯アプリ NOeSIS コラボレーションカフェ

NOeSISとは

注文したもの

  • 憂姫ちゃん ホットココア + USHIマグカップ
  • 一夜先輩 鏡の中のヨーグルトご飯

店内
店内 店内

ヨーグルトご飯とUSHI
ヨーグルトご飯とUSHI
ヨーグルトご飯、すっっっっっっっっっごいおいしい!!

clock2016-08-03

今日は高坂穂乃果ちゃんの誕生日です

今日は高坂穂乃果ちゃんの誕生日です

 今日は高坂穂乃果ちゃんの誕生日です!!
おめでとう!!

 うちのゴリラ(bot)さんも穂乃果ちゃんをお祝いしています。

リファレンス

clock2016-07-30

可愛い女の子にコマンドラインの実行終了を音声通知して欲しかっただけなんだ

可愛い女の子にコマンドラインの実行終了を音声通知して欲しかっただけなんだ

 前回、コマンドラインの実行終了時にワガハイが流れ出すaliasを作ったけど、 実はあれには重大な問題があり、つまり作業がワガハイを観ることにシフトしてしまうという。

とはいえCLIでの作業に萌えは欠かせないので、可愛い音声で実行終了の通知をしてもらうことにした。

喋らせる

 Linux…

clock2016-07-21

コマンドラインの作業が終わると、突如としてワガハイ1話が流れ出すalias作った

コマンドラインの作業が終わると、突如としてワガハイ1話が流れ出すalias作った

#/usr/bin/env zsh
alias mnotify="mplayer 'path/to/ワガハイ1話のファイル' > /dev/null 2>&1"

こうやって使う。

$ stack build ; mnotify

すごい

 mplayerコマンドを実行してるだけなので、突如として音声が発生し、画面トップにも現れるので最高。
便利。

clock2016-07-19

今日のgit-tips (簡単で便利なrebaseによるcommit編集)

今日のgit-tips (簡単で便利なrebaseによるcommit編集)

 今日は未pushのいくつかのcommitの内容をgit rebaseで編集する方法を紹介します。
push済みのcommitは編集…できますが、git push --forceをする必要があります。

 git push --forceが何かというと、複数人で共同作業をしているリポジトリの場合に、他の作業者を混乱させるコマンドです。
1人用リポジトリでも、--force…

clock2016-07-12

Firefoxをアップデートしたらfcitxが動かなくなったので

Firefoxをアップデートしたらfcitxが動かなくなったので

解決

 Firefoxのバージョンとしては47.0.1だけど、多分43より後のバージョンでは発生する…うちの環境では。

  • うちの環境
    • Arch Linux 64bit
    • pacman -Syu したばかり

解決方法としては、~/.xinitrcに以下を記述します。 それだけ。

export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx
export DefaultIMModule=fcitx

僕の.xinitrcはこんな感じ。 exec startxfce4の後にexport…

clock2016-07-06

シェル環境をbash-viからzsh-viinsに移行している

シェル環境をbash-viからzsh-viinsに移行している

今までのシェル環境

  • bash
    • set -o vi (viキーマッピング)
    • vi-commandとvi-insertを使い分け
    • vi-insertはEmacsライクなカーソル移動を手動定義してる
    • プラグイン
      • プラグインマネージャ無し
      • 自作プラグインはdotfilesのみに集約
  • tmux

これからのシェル環境

  • zsh
    • bindkey -v (viinsキーマッピング)
    • zshのviinsはvi同様にEscやC-[でvicmdモードに出れる
    • viinsはEmacsライクなカーソル移動を手動定義してる
    • プラグイン
      • zplug
      • 自作プラグイン用にリポジトリを作成
  • tmux
clock2016-06-26

はいふりスタンプラリーにお母さんと行ってきた

はいふりスタンプラリーにお母さんと行ってきた

 ハイスクール・フリート スタンプラリーにお母さんと行ってきました。

 朝07:00に家を出て、夜22:00くらいに帰るというなんとまあ健康な生活を何ヶ月ぶりにしたことか。

順路

  1. メイちゃん
  2. もかちゃん
  3. ミケちゃん
  4. シロちゃん
  5. ココちゃん
  6. リンちゃん
  7. ミーちゃん
  8. タマちゃん
  9. マロンちゃん

result

そこにある価値、立ちはだかる困難、そしてそこにある価値

 行きの電車でパンを食べる、おいしい。
我々はメイちゃん駅でスタンプラリー台紙を手に入れる。

clock2016-06-25

ニコ生配信環境が降ってきたので配信した

ニコ生配信環境が降ってきたので配信した

 環境は以下。

  • OS: Arch Linux

 OBSでALSAの設定するのに手間取っていた。 ニコ生の音声をマイクで流したければ、OBSで設定すればいいだけだった。

clock2016-06-24

NOeSIS01リメイクAndroid版が配信されたのでPC上で動かした

NOeSIS01リメイクAndroid版が配信されたのでPC上で動かした

 ドーモ、人です。

 NOeSIS嘘吐きリメイク版が配信されたとなると、 もちろんリリース後最速組として直ちに購入、端末で起動をしなければならないというものです。
なのでPC上でAndroid版NOeSIS01リメイクを動かしました。

NOeSISって?

 NOeSIS…

clock2016-06-19

FJBOBという謎の勉強会に行ってきた

FJBOBという謎の勉強会に行ってきた

About

 謎の人間達が集まり、各々のテーマについてロングトーク及びLTをする会。
参加人数は20人ほど。

 謎なので開催場所も参加表明方法も謎です。

Agenda

※ 資料が公開済みの場合のみリンク付き

発表者名 タイトル
石川さん プログラムを楽しもう!
げんくん Archでもできるよ! OpenStack
キリンさん 日本人が大好きな事例で学ぶPowerShell, PowerCLI
なかでぃ Laravel5とかいうヤツ
clock2016-06-17

HackageにHaskellライブラリを上げてみた

HackageとHaskellライブラリを上げてみた

Hackageデビュー。

 stackageにもPR(stackageへのパッケージ登録申請)を送りたかったのですが、sentence-jpはCライブラリであるmecabに依存しているので… (sentence-jpが依存しているパッケージ(hsmecab)がmecabに依存している)

clock2016-06-12

友人家でWebハッカソンをしてきた

友人家でWebハッカソンをしてきた

ガルパンを視聴する様子

1
2
3


くまみこを視聴する様子

4


楽しかったです。

clock2016-06-04

ブログをFC2ブログからHakyll + github-pagesを使うようにした

ブログをFC2ブログからHakyll + github-pagesを使うようにした

 以前書いた 退職記事 がありましたが、あれはpandocでmarkdownからhtmlに変換してからFC2ブログに投稿していました。

しかし事件がここで起こり、具体的にはolとulがネストしている部分のStyleがだめになっていました。 ありふれたhtmlの果て

ブログ環境を・・・ウッ・・・ガエダイ!!!

作業

clock2016-05-26

C#で仕事してましたが退職しました

C#で仕事してましたが退職しました

先ほど正式に退職をしてきました。
N社は僕が2年制の専門学校を卒業し、新卒で入社し丁度2年間務めた初めての入社先でした。

 この記事は備考録がてら、僕の職歴やポエムを書いたものです。


  1. N社での主な職務
  2. 休職に向けた引き継ぎ作業
  3. 次の入社に向けた想い
clock2015-11-22

よさがぴょんぴょんするんじゃあ〜 in VimConf2015

よさがぴょんぴょんするんじゃあ〜 in VimConf2015

 VimConf2015に行ってきました。 VimConf2015 is koko .

今日の皆様の発表資料まとめ

Vimのgitへの移行について

koron氏。
今年にVimがいかにしてgitへ移行したかの内部事情を聞けた。
スライドについては僕もまだ見てないんです。
なんで会場にいたのにスライドを見ていないのかって?
諸事情によりスライドが写せなくなったものの、 koron氏がトークのみで発表を行ったから…。

clock2015-10-15

蒼樹うめ展に行ってきましたっ!

 まず、上野駅には9:30くらいにつき9:45にはうめ展入場列に入ったのですが
入場には3時間以上かかりました!

その後観覧に3時間、物販待機に5時間程度かかりましたが
そんな辛さなんのそのという楽しみを感じさせていただき、非常に幸せな時間を過ごすことができましたっ!!

 帰ってきた今、とても晴れやかな気分でいます!
スタッフの皆さん、うめてんてー、皆さんありがとうございましたっ!!

clock2015-08-19

TypeScriptでjQueryを扱う with tsd

TypeScriptでjQueryを扱う with tsd

jQueryだけでなく、angular.jsなども使えます。

  • tsd : JavaScriptファイルをTypeScriptで扱うための型情報ファイルを簡単に落としてこれる

    • 型ファイルはここから落とされる
  • 前提条件

clock2015-08-15

Ubuntu15.04にnodejsとtypescriptを入れた

Ubuntu15.04にnodejsとtypescriptを入れた

目的 : TypeScript実行環境を整える

1. どのパッケージをインストールすればいい?

参考ページ
http://y-anz-m.blogspot.jp/2012/11/ubuntu-typescript.html

ただしリポジトリを追加する必要はなかった
実際に行った作業は以下の通り。
これを実行するとnpm…

clock2015-08-02

C#の拡張メソッドやScalaのimplicit convertionで広域な型を指定してはいけない

静的型付けの中で型を忘れた話

 数日前、社内でこんな事件があった。

テスターさん「あいやさん、このチケット#XXXのテストをしようと思ったら、そもそも画面Aに飛べないんですけど…」
僕「ゑ?」

( 今うちではRedmineチケットでテストしてもらいたい項目を投げたりして管理してます。
他にいい方法あったら教えてください )

 その画面は、今回の仕様変更で実装した部分には直接的に関係ない部分だった。

clock2015-07-13

Vim_scriptで定数

Vim scriptで定数

let A = 10
lockvar A
let A = 20  " 例外

これでできるらしい。
ただし、これでできるのは「変数への書き込み禁止」であって
書き込み禁止を解除することが可能。

let A = 10
lockvar A
unlockvar A
let A = 20  " 通る

なので、強制力はないけど意味力のある変数…って感じになる。

まとめるとこう書ける。

let A = 10 | lockvar A

さらに注意として、間接的に他の辞書などを書き換え禁止できない。

let B = {'bar' : {'baz' : 30}} | lockvar B
let B.bar.baz = 40  " 通る
let C = {'hoge' : [10]} | lockvar C
let C.hoge[0] = 20  " 通る

もちろんこういう対策もできるはできる。

let D = {'ahoge' : [10]} | lockvar D | lockvar D.ahoge[0]

便利。


追記

強者さん達に助言をいただきました。

筆者プロフィール

my-latest-logo

aiya000(あいや)

せつラボ 〜圏論の基本〜」 「せつラボ2~雲と天使と関手圏~」 「矢澤にこ先輩といっしょに代数!」を書いています!

強い静的型付けとテストを用いて、バグを防ぐのが好き。Haskell・TypeScript。