2018年サブスクリプション課金まとめ

2018年に使ったサービスなどまとめ

aws

4000¥/year? ドメインとかおいてあるだけなので、一旦解約するかも

PLAYSTATION NETWORK

5,200¥/year

PSN+オンラインゲームに必要なやつ かなりゲームしてるのでペイしている。

netflix

1,296¥/month = 15000¥/year 途中で値上がりしたの辛いね 年額にするとちょっと高く感じるけどだいぶ使っているのでよし

kindle unlimited

980¥/month = 11760 ¥/year

月3〜4冊は少なくとも読んでいそうだけど、prime readingと被っている範囲はありそう 解約を迷い中

apple music

9800¥/year

年間一括払いでお得 ペイしてんじゃないかなぁ〜

GITHUB INC

7$/monthで使っていたけど、個人のprivate repoへのcommitがなくなったので10月ごろ解約

ダーツライブ

324¥/month

使ってなかったので10月ごろ解約

ドメイン

7000¥/yearぐらい

使ってないのに払ってるドメイン多すぎでは???

Webの自治

1

Webやってる人います?僕はやってます。というかWebが好きなので。

ブラウザ上で動く何かって難しい、とは言え自分もわかんない。

この難しさってなかなか表現しづらくて今まで言葉にすることを躊躇ってきた感じがする。

でも個別のことに対しては文句は言ってきた。例えば、古いのだと右クリックを禁止しているサイトとか、最近だといきなり通知の許可/非許可を出してくるサイトとか。

だけど、全体を通したルールのようなものってなかなか自分の中で明確に持ててない。

結局Webは自由だからなーみたいなのも真ではあるから、これは全員絶対禁止みたいなルールってダサいし。

だけど自分でWeb作ってる時ぐらいは持ちたい。

書いている今現在あるわけではないけど。

2

表示する上で何を満たしていたらいいかって難しい。

Webがどう表示されるかって多様なので全て満たすのは難しいにしても、いろんな人にWebして欲しいから気持ちとしては対応したくなっちゃう。

PCとかスマフォのブラウザなんか序の口で、たとえばプリンターで紙にプリントされたものとかブラウザが乗ったTVとかPS4とかKindleとかApple TVとか音声ブラウザとか

”ビジネス”Webは主要ブラウザ対応でオッケーみたいな世界観で語って悲しくない??

どういう人がどう使うかという点を議論せずにブラウザシェアで語っちゃうのってヤバくない??

3

まぁ全部盛りって無理だけどね。

多くの企業向けSaaSでAppleTV対応って意味がなく思える。流石にAppleTVで仕事している人見たことないから

開発しててもChromeだけ対応の方が楽すぎるし、IEに対応してくれって言われるだけでその場で血を吐いて死ぬ発作が出るかもしれない。

それでもアクセスする人全員に向き合ってなんとか使いやすいようにしてあげたい。

だからこそヌルい実装とか仕様を見ると辛い気持ちになる、けどルールがない

4

何を求めているのかわからないけど、 AndroidiOSのデザインガイドラインという言葉は多分近い、けどUXという言葉からは遠い。

いや、"UX"っていう言葉が企業からすると「どれぐらい儲かりそうか」でユーザーからすると「使っていて腹たった」みたいな意味で使われているせいかもしれないけど。

相貌失認

1

インターネットがもうちょっと昔にあったら便利だったので自分の事例を共有するシリーズ

今日は相貌失認

相貌失認 - Wikipedia

ざっくり言うと人の顔がわからなくなる障害

自分は明確に相貌失認の感じと言う訳ではなないと思う。酷い症状ではないなので本当にそうか自信がない。

人間の脳に人の顔を認知する機能があるのだろうがこの機能がおそらく弱い。

弱いと言っても、どの程度人の顔が認識できないかと言う点は数値化しにくいように感じる。

自分の場合いくつか例があって

  • その場にいない人間の顔を比べることができないようで、誰と似ているとか言う感覚を共有できない
  • 人を間違える、他の人からすると似てない人を似ていると言ってしまう。
  • すれ違った人が知人かどうかわからない
  • 親の顔やよく知っている人の顔を思い浮かべても出てこない

ただ上記の症状があっても、男女の区別はつきやすいし表情がわからないこともない(と信じている)

他に上記の症状に含めることを迷うとではあるが、

顔の可愛さがあまり共感できないことが多く橋本環奈も結局どれかわからない。

今さっき調べて見たが、よくいる人ぐらいにしか認識できないのでおそらく明日には忘れてしまう。

おそらく細かいパーツまでは認識できているが、そこから統合できないの原因と思う。人種の違いはまだわかると思うので。

こういうことを言うと怒られが発生するが、野球選手の清原に似ていると思った。そう思って清原を画像検索で調べて見比べると確かに違うことはわかる。

2

なので自分の知っている人が街とか普段会わないような場所であった際になるべく誰なのか言ってくれると助かります。

いつも同じ服を着ている人や髪型が特殊、もしくは体形が標準から外れている人は大丈夫です。

あと、DAIGOとJOYの違いがガチでわからないで教えてください。

南青山

1

焼けた栗を素手で拾うようなテーマになってしまうけど。

反対派とか賛成派とかそういう話でもなく、どちらかといえば自分の話。

2

田舎の公立の小学校と公立の中学校で育った。

地域の中ではまだ平和の方の中学だったけど、東京に出てから聞いた感じではそんなに治安が良くなさそうな感じ

親は“公立の中の雑菌の環境”(と表現された)で育てたいという気持ちからそうなったらしい

とはいえ、僕の地域で私立の中学に入れようとするのは相当な教育家庭だが

僕は真面目なほうだったのであまり居心地が良くはなかった

もし自分に子供がいたら私立に通わせると思う

でも自分が急な引っ越しとかでいい感じの育ちの所に行って適応できるのかな不安な気持ちもある

実際カルチャーが違いすぎる気がするし、向こうから見たら僕からみて不良と違いがつくのだろうか

荒い環境にいたから暴力とかもあまりに慣れてしまっているし、言葉も向こうからしたら違う

そういうのも“育ちのいい”人はカバーできるんですかね?

松嶋尚美のコメントを見て「あっ体罰とかない前提の話なんだ」って思った

VSCodeでOCaml周りの設定をしていた話

1

以前はAtomとNuclidを使っていたんだけどこの前の初期化の際にVSCodeにしてから設定していなかったのでしようとした

今の設定は以下のようになっていて

github.com

使おうとしているpluginは reasonml-editor/vscode-reasonm

github.com

nix-darwinで諸々の依存を入れたので、

    "reason.diagnostics.tools": [
        "bsb"
    ],
    "reason.path.ocamlmerlin": "/run/current-system/sw/bin/ocamlmerlin",
    "reason.path.ocamlfind": "/run/current-system/sw/bin/ocamlfind",
    "reason.path.ocpindent": "/run/current-system/sw/bin/ocp-indent",
    "reason.codelens.enabled": true

という感じの設定にした。

2

しかしBuckleScript周りが悲しいことに以下のようになる

f:id:hiroqn:20181222233641p:plain

これはIssueに上がっているみたいだった

github.com

最初merlinの設定がおかしいのかと思ったが、

Merlin doesn't provide syntax highlighting nor indentation.

どうやら非対応らしい

自分の認識ではBuckleScript中のjsとの間をいい感じにしてくれる [@@bs.deriving abstract]などはppxの構文の範囲だと認識しているのでいい感じにやって欲しい

ここら辺Atom+Nuclidでは問題がなかったように記憶しているので少し悲しい。

BuckleScriptのweb上でのPlaygroundはbsc.exeをjs_of_ocamlコンパイルしたものが使われていたはずで、同じようなノリでbsc中のparser部分だけどpluginに持ってくることは可能に思えるがかなりめんどくさそうだ。

ていうかreasonだと問題起きなさそうなのが悲しい。

3

実はまだファイルをまたいだ依存関係がうまく設定できていない。

Module A中でModule Bに飛びたい時に同一ファイルでは飛べるのにファイルをまたいでは飛べない。

ハイライトがぶっ壊れているのは関係はなさそう

f:id:hiroqn:20181222235245p:plain

####{BSB GENERATED: NO EDIT
FLG -ppx /Users/hiroqn/.dev/bs-winston/node_modules/bs-platform/lib/bsppx.exe
S /Users/hiroqn/.dev/bs-winston/node_modules/bs-platform/lib/ocaml
B /Users/hiroqn/.dev/bs-winston/node_modules/bs-platform/lib/ocaml
FLG -nostdlib -color always
FLG -w -30-40+6+7+27+32..39+44+45+101
S src
B lib/bs/src
####BSB GENERATED: NO EDIT}

merlinの設定がおかしい可能性もあるがatom時に問題が起きたことはなかったのと .merlin自体が自動生成なのでその可能性は低そうである。

4

という感じでいまいち設定がうまくいかなかったのでAtomに戻ることになってしまいそう。

5 追記

今さっき.merlinがどのコンパイラを使うか指定がないことに気づき、急いでmerlinなどをbucklescriptにあるocamlでビルドし直したところ動きましたわ〜

{
  "reason.path.ocamlfind": "/nix/store/jgd4fwcg1d58kghgmfdfdck5fqn0mwi0-ocaml-findlib-1.8.0/bin/ocamlfind",
  "reason.path.ocpindent": "/nix/store/hg8rvg4x6hd2058wcfnwprs9d379gdv3-ocaml4.02.3-ocp-indent-1.6.1/bin/ocp-indent",
  "reason.path.ocamlmerlin": "/nix/store/bz5qmz0d8gqlvhv7m9x8yi5c7dr94bfk-ocaml4.02.3-merlin-3.2.2/bin/ocamlmerlin"
}

こんな感じね

まだハイライトぶっ壊れたままだけど

fp-tsの続き

1

昨日の続きです。

hiroqn.hatenablog.com

昨日のShowはあくまで標準主力にOutputされることを意識したインターフェースでした。

これです。

export class Show<A> {
    public readonly _tag: 'Show' = 'Show';
    public readonly _A!: A;
    public readonly _URI!: FsFURI;
    constructor(readonly message: string, readonly more: A) {}
}

これをWriterのようにあとですべてのmessageを取得するように変えたい時にどうすれば良いでしょうか。

実はinterpretTaskEitherTaskEither<string, A>というMonadになっているのは、Free型を解いていく際にMonadのchainを使って継続させているためのなのです。

昨日のfoldFreeの第一引数がMonadになっているのはそう言った理由です。

一旦


function tell(message: string) {
    return function<A>(x: A) {
        return free.liftF(new Show(message,  x));
    }
}

const program = read('./package.json').chain(content => tell(content)(content)).chain(content => write('./package2.json', content)));

と書き換えてみます。

今回のShow型のmessageがstring[]というMonoidに足されていくように解釈して欲しいので

TaskEither型にWriterTを使って TaskWriterEither<string, string[], A>のような型とMonadにするためのchain関数があればいいのですが

すみません!!!時間不足でできませんでした!!!

fp-tsとfree

1

fp-tsにはFree Monadを使っていきたいと思います。

Free Monadに関する説明は今回は省きます。

Free Monadと書いていますが、実はFreerMonadという感じがしていますがfp-tsがFreeという表現になっているのでFreeでいきます。

2

今回作るのは下のfp-tsのexampleや以下のgistを参考にしてPromiseを使った例を作っていきます。

検索した感じではPromiseを使った例がなかったので。

github.com

Free Monad example, Flow and fp-ts, npm install fp-ts · GitHub

3

fileのread, write周りを例に今回は作っていきます。

実はデータ型を定義するところまでは一緒です。それがFreeの強みなんですが

declare module 'fp-ts/lib/HKT' {
    interface URI2HKT<A> {
        Fs: FsF<A>;
    }
}

export const FsFURI = 'Fs';

export type FsFURI = typeof FsFURI;

export class Read<A> {
    public readonly _tag: 'Read' = 'Read';
    public readonly _A!: A;
    public readonly _URI!: FsFURI;
    constructor(readonly path: string, readonly more: (p: string) => A) {}
}

export class Write<A> {
    public readonly _tag: 'Write' = 'Write';
    public readonly _A!: A;
    public readonly _URI!: FsFURI;
    constructor(readonly path: string, readonly content: string, readonly more: A) {}
}

export class Show<A> {
    public readonly _tag: 'Show' = 'Show';
    public readonly _A!: A;
    public readonly _URI!: FsFURI;
    constructor(readonly message: string, readonly more: A) {}
}

export type FsF<A> = Read<A> | Write<A> | Show<A>;

function read(path: string) {
    return free.liftF(new Read(path, identity));
}

function write(path: string, content: string) {
    return free.liftF(new Write(path, content, undefined));
}

function show(message: string) {
    return free.liftF(new Show(message, undefined));
}

こういう感じになります。

あとはこれを解釈する部分を作っていきます。

Promiseをfp-tsで使う場合、選択肢としてTask or TaskEitherになるのですが一応真面目にError処理ができるTaskEItherを使っていきます。

FsF<A> => TaskEither<string, A>となるように型を合わせれば動くと思います。

function interpretTaskEither<A>(fa: FsF<A>): TaskEither<string, A> {
    switch (fa._tag) {
        case 'Read':
            return new TaskEither(
                new Task(async () => {
                    try {
                        const file = await fs.promises.readFile(fa.path, { encoding: 'utf8' });
                        return right(fa.more(file));
                    } catch (e) {
                        return left(`read error: ${e.message}`);
                    }
                }),
            );
        case 'Write':
            return new TaskEither(
                new Task(async () => {
                    try {
                        await fs.promises.writeFile(fa.path, fa.content);
                    } catch (e) {
                        return left(`write error: ${e.message}`);
                    }
                    return right(fa.more);
                }),
            );
        case 'Show':
            return fromIO(
                new IO(() => {
                    console.log(fa.message);
                    return fa.more;
                }),
            );
    }
}

あとはfoldFreeするだけです。 foldFreeに渡す値が型を見た時にわかりにくいのが難点で、ぱっと見理解するのがかなり難しめにできています。

export declare function foldFree<M extends URIS3>(M: Monad3<M>): FoldFree3<M>;
export declare function foldFree<M extends URIS3, U, L>(M: Monad3C<M, U, L>): FoldFree3C<M, U, L>;
export declare function foldFree<M extends URIS2>(M: Monad2<M>): FoldFree2<M>;
export declare function foldFree<M extends URIS2, L>(M: Monad2C<M, L>): FoldFree2C<M, L>;
export declare function foldFree<M extends URIS>(M: Monad1<M>): <F extends URIS, A>(nt: <X>(fa: Type<F, X>) => Type<M, X>, fa: Free<F, A>) => Type<M, A>;
export declare function foldFree<M>(M: Monad<M>): <F, A>(nt: <X>(fa: HKT<F, X>) => HKT<M, X>, fa: Free<F, A>) => HKT<M, A>;

ですが先ほどTaskEither型を使っているので、TaskEitherが定義されているところにある

export declare const taskEither: Monad2<URI> & Bifunctor2<URI> & Alt2<URI> & MonadIO2<URI> & MonadTask2<URI>;

を使えば大丈夫です。

つまり今回は型からわかるように以下の定義を使っていることがわかります。

export declare const taskEither: Monad2<URI> & Bifunctor2<URI> & Alt2<URI> & MonadIO2<URI> & MonadTask2<URI>;

最終的に実行する部分は以下のようになります。

const program = read('./package.json').chain(content => show(content).chain(() => write('./package2.json', content)));

async function main() {
    const result: Either<string, undefined> = await free
        .foldFree(taskEither)(interpretTaskEither, program)
        .run();

    if (result.isLeft()) {
        return console.error(result.value);
    }
}

今回TaskEitherを使っているのでawaitの部分でcatchする必要がありません。もしTaskを使っていた場合catchする必要があります。

今回のcodeはgistにあげてあります。

FreeFs.ts · GitHub

package.jsonがある環境ではfileの中身が標準出力に出されて、package2.jsonが作られていると思います

package.jsonがない場合、read error: ENOENT: no such file or directory, open './package.jon'以下のようなerrorになると思います。