Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

Reactのリハビリがてらアプリ作った記録

卒業研究とか部活に追われてあまりReactとか触れていなかったのでリハビリのつもりでやった。1日でガーッと書いたときの記録。コケたところとかも(どうせ後でまた同じところでコケるので)記録しておく。

どういうアプリ?

graphemesplitという、Unicodeで1文字をカウントするライブラリがある。それを使って文字数をカウントするだけのアプリ。ロジック部分はほぼないに等しいので、主にビューを作り込んでいた。

文字数カウント

作ってるとき思ったこと

今回はファイル分割すらせず1ファイルに全て書いた。70行以下に収まっているし、これくらいなら分割するほうが面倒。このファイル、かなりまとまっているし、結構あとあとまでテンプレートとして使いまわせそう。

流れとか

  1. 前につくったプロジェクトからwebpack.config.jsだとか色々引っ張ってくる
  2. それを眺めながら適当に叩いて直していく
  3. 形ができてきたらTypeScriptを導入(本当にビューしか書いていないので、React.FCくらいしか型が出てこないけど)
  4. バンドルサイズが大きすぎるからPreactを導入してみようと試みる

Preact導入

流れ見てもらえばわかるけど、Reactで書いた後にPreactを導入することにしたので、Reactから移行する方法について調べた。

Getting Started – Preact

どうやらpreactをインストールして、webpack.config.jsのresolve.aliasに設定するだけでいいみたい。TypeScriptの型もそれで通った。不要になったのでreactreact-domをアンインストール。

コケた部分

TypeScript導入したらビルドできなくなった

これはめっちゃカンタンに解決できた。

import React from 'react' -> import * as React from 'react'

これだけ。

styled-componentsが効かない

styled-componentsはclassを振るので、それを受け取っていないと効かない

// NG
// const Component = (props) => <h1>{props.value}</h1>;

// OK
const Component = (props) => <h1 className={props.className}>{props.value}</h1>;
const StyledComponent = styled(Component)``;

設定ファイルどれを書けばいいんだ…

awesome-typescript-loaderを導入している場合、babelrcとかは要らなくて、webpack.config.jstsconfig.jsonだけあれば良い。babel関連はtsconfig.jsonに書いて、webpack.config.jsはその辺を気にしなくてよい。

input[type=checkbox]ってどうReactで扱えばいいんだ?

まあ何にも考えずに書くならこんな感じでOK

const CheckboxComponent : React.FC<{}> = () => {
    const [flag, setFlag] = useState<boolean>(true);
    return (
        <label>
            <input type="checkbox" checked={flag}
                onChange={() => setFlag(v => !v)}/>
            フラグ{flag ? 'onだよ!' : 'offだよ!'}
        </label>
    );
};

もうちょい捻るとこんな感じ

type Props = {
    value: boolean,
    onChange: (events: React.ChangeEvent<HTMLInputElement>) => void,
};
// 外部からonChangeとvalueを受け取る
const CheckboxComponent : React.FC<Props> = ({value, onChange}) => {
    const [flag, setFlag] = useState<boolean>(true);
    return (
        <label>
            <input type="checkbox" checked={value}
                onChange={onChange}/>
            フラグ{flag ? 'onだよ!' : 'offだよ!'}
        </label>
    );
};

イベントハンドラの型わかんねえ…

まず、関数の型はこんな風に書ける。

type Props = {
    value: string,
    onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => void,
};

型についてはVSCodeとかだとマウスオーバーすると出てくる。ありがたい時代になったものだな…Vimにもこの機能欲しいしちょっと調べるか

依存関係

  • @babel/core
  • awesome-typescript-loader
  • webpack
  • webpack-cli
  • typescript
  • @types/react
  • @types/react-dom

  • preact

  • styled-components

これだけで出来るんだな…すごい

一発ネタだし、今回は特にテストとか書くつもりはない。

リハビリがてらやったけど、結構サクサクと書けて楽しかった。

まじかる☆ベーカリーのパンはどれほどの確率で焼けるのか?

www.youtube.com

こちらは僕が好きでよく見ている動画です。まじかる☆ベーカリーというボードゲームで遊ぶ動画です。

このゲームは「パン」を焼き上げて得点をもらうゲームとなっており、パンにはそれぞれ焼き上げるための条件が書かれています。たとえばコッペパンは「サイコロを2つ振って合計8以上」なら焼き上げ成功となります。

しかし、動画を見ているうちにふと「あれ?確率がどれも1/2以下なのでは?」と気になってしまったのでプログラミングをして計算してみました。

続きを読む

JSでHaskellのMaybeモナドを再現してみた

Haskell的な書き心地を再現しようと試みてみました。結果、かなりいい感じに仕上がりました。

// Haskellでは
// Just 3 >>= return . (+ 3);

// JSだと
Maybe.Just(3) .bind (compose(return_, v => v+3) ); // 似てる!!

Maybeモナド

結構えらい実装になりました。

class Maybe {
    constructor(type, value) {
        this.type = type;
        this.value = value;
    }
    bind(f) {
        if (this.type == 'Nothing')
            return Maybe.Nothing();
        return f.bind(this)(this.value);
    }
    static Just(v) {
        return new Maybe('Just', v);
    }
    static Nothing(f) {
        return new Maybe('Nothing', '');
    }
}

ここまでは良いのですが、以下はかなりテクニカルな実装になりました。。

function liftM(f) {
    // liftM f m1 = do x1 <- m1; return $ f x1
    return this.bind(x1 => this.return(f(x1)));
}
function ap(m) {
    // ap f m1 m2 = do x1 <- m1; x2 <- m2; return $ f x1 x2
    return this.bind(x1 => m.bind(x2 => this.return(x1(x2))));
}
Maybe.prototype.return = Maybe.Just;

// instance Applicative Maybe where
//     pure  = return
//     (<*>) = ap
Maybe.prototype.pure = Maybe.prototype.return;
Maybe.prototype['<*>'] = ap;

// instance Functor Maybe where
//     fmap = liftM
Maybe.prototype.fmap = liftM;

まず、return関数をMaybe.prototype.returnとして組み込みました。returnをstatic関数でなくメソッドにしたのは、利用する関数側からコンストラクタの特定をするのが面倒だからです。たとえばreturnがstaticなら、ap関数のなかでthisのコンストラクタを特定して、それのreturnを呼び出す流れになります。それよりも、thisに生えているreturnをそのまま呼び出すほうが楽ですよね。

次に、apやreturn_を関数として定義しています。これらはメソッドとして利用する想定なので(m.fmap(f)のように使いたい)、アロー関数で定義するとthisを参照できなくなります。そのため、functionキーワードを用いて定義しました。久しぶりにfunctionと書いた気がします。

Maybeモナドを使ってみる

使い心地はかなりHaskellに近くなっています。

function return_(...args) {
    return this.return(...args);
}

function compose(...fs) {
    return function (v) {
        for (const f of fs.reverse()) {
            v = f.bind(this)(v);
        }
        return v;
    };
}

// Just 3 `fmap` (*3)
Maybe.Just(3) .fmap (v => v*3);

// Just (*3) <*> Just 3
Maybe.Just((v) => (v*3)) ['<*>'] (Maybe.Just(3));

// Just 3 `bind` return . (+ 3)
Maybe.Just(3) .bind (compose(return_, (v) => v*3));

結構似ていますよね!!!我ながら頑張ったと思います。

まあでも、JSがデフォルトで部分適用できなかったり、演算子を関数として使えなかったり、言語仕様の時点でかなり再現が難しいので、こんなことはしなくて良いと思いました。

HTTPieを使いこなすためのサンプル集

問題という形でまとめてみました。

パラメータ付きGET

  • httpbin.org/getにGETメソッドでリクエスト
  • name=Johnage=29というパラメータを渡す

JSON形式でデータを渡す

  • httpbin.org/postにPOSTメソッドでリクエスト
  • リクエストのヘッダにContent-Type=application/application/jsonをつける
  • nameフィールドにJohn
  • ageフィールドに29(数字)
  • hobbiesフィールドに["http", "pies"]を入れる

フォーム形式でデータを渡す

  • httpbin.org/postにPOSTメソッドでリクエスト
  • リクエストのヘッダにContent-Type=application/x-www-form-urlencodedをつける
  • nameフィールドにJohn
  • ageフィールドに29を入れる

画像をフィールドに入れる

  • httpbin.org/anythingにPOSTメソッドでリクエスト
  • リクエストのヘッダにContent-Type=application/x-www-form-urlencodedをつける
  • imageフィールドに適当な画像を添付

localhostにリクエストをする

まず、$ python -m http.serverなどでローカルにwebサーバーを建ててください。そして、建てたサーバーへアクセスしてください。

  • localhost:8000へGETメソッドでリクエスト

HTTPヘッダを編集する

  • httpbin.org/getへGETメソッドでリクエスト
  • リクエストにX-API-Token: 3というヘッダを付け加える

Digest認証してみる

  • httpbin.org/digest-auth/auth/username/passwordにGETメソッドでリクエスト
  • Digest認証する

リダイレクト途中のリクエストをすべて表示する

  • httpbin.org/redirect/2にGETメソッドでリクエスト
  • 2回リダイレクトが起こるので、追従する
  • 途中のリクエストのヘッダも表示する

AtCoderで水色になりました

水色記念に書いておきます

f:id:panda_noir:20191222232006p:plain

競プロ歴

AtCoder歴は半年…というと微妙ですが、ちゃんと取り組みだしてから半年ですね。高校生のときに蟻本で挫折しているので、競プロにはじめて触れたの自体はAtCoderができるより前です。

水色になるまでに取り組んだこと

ABCの300点問題、400点問題をだいたい埋めました。ただ、difficultyが1600以上の問題はあまり解けていないです…

あとは螺旋本に取り組んでいます。ただ、後半に差し掛かってから手が止まってしまっています。あまりコンテストで見たことのない範囲でやる気が出ないのが原因ですね…

最近実力が停滞してきている感じがするので、なんとか打破したいのですが、思考力を鍛えるという抽象的なことにどう取り組めばいいのですかね…とりあえず500点問題を埋めていったりするのが早い気がしますが。

愚痴

ここからちょっと愚痴になります。緑になってから水色になるまで停滞している期間があったのですが、その期間についてですね。

f:id:panda_noir:20191222232236p:plain

この赤で囲った部分が停滞している部分です。なんとこの期間にABCに2回しか参加できなかったのです!土曜日にバイトを入れていたのが大きな原因ではあったのですが、シフトがなくなっても日曜日にABCがズレて参加できなかったり、ABCではなく高レート帯向けのコンテストだったり、ABCと全然噛み合いませんでした。

ここまでABCと噛み合わないとさすがに嫌がらせみたいでだいぶ気が滅入りましたね…というか未だにあまり立ち直れてません。

この停滞期間にもう少しABCがあればもっと早く水色になれていたんじゃないかと思うとなんだかやるせないですね…つらい。

以上です。学生のうちになんとか水色になれてよかったです。

次の目標

まずは青になりたいです。ここ最近のコンテストを見ていると、だいたい

  • 400点まで30分前後で早とき
  • 500点が解けている

このくらいが1500〜1700パフォくらいのようなので、まずは400点までの早とき、そして500点を2回に1回は通せるくらいの実力を目指します。