(´ワ`)

主に技術系備忘録、たまに日記。

Rustのスマートポインタまとめ

最近まじめにRustを勉強し始めたので主要なスマートポインタについてRustドキュメントの内容を自分用にまとめる。

Box<T>

T の値をヒープに格納する。型の中に同じ型が入るような無限の再帰ループを起こすような型のように、 T のサイズが未確定のときに使える。RustドキュメントにはConsが例として挙げられている。

enum List {
  Cons(i32, List),
  Nil,
}

fn main() {
  use List::{Cons, Nil};
  let ls = Cons(1, Cons(2, Cons(3, Nil)));  // Consの中にConsが入っており再帰的構造になっているので、コンパイラが必要なデータのサイズを計算できない
  println!("{:?}", ls);
}
enum List {
  Cons(i32, Box<List>) // Boxで定義することで再帰的構造を計算できる
  Nil
}

fn main() {
  use List::{Cons, Nil};
  let ls = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil)))));
  println!("{:?}", ls);

Boxはポインタとして間接参照されるのでポインタがデータ構造の代わりに格納される。そのためデータの中身がどのくらいの量であるか関係なくコンパイラが解釈してくれる。

Rc<T>

Referencecounter。
複数の参照を可能にするスマートポインタ。参照されている数をカウントする機能も持っており(string_count(), weak_count)、このカウントが0になったとき自動で破棄されるようになっている。先程のConsを例にすると、以下のようなことができる。

#[derive(Debug)]
enum List {
    Cons(i32, Box<List>),
    Nil,
}

fn main() {
    use List::{Cons, Nil};
    let ls = Box::new(Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil)))))));
    println!("{:?}", ls);

    let ls2 = Box::new(Cons(3, ls));  // この時点で所有権がls2へ移る
    println!("{:?}", ls2);

    let ls3 = Box::new(Cons(4, ls));  // ls2へ参照権が移っているのでエラー
    println!("{:?}", ls3);
}
use std::rc::Rc;

#[derive(Debug)]
enum List {
    Cons(i32, Rc<List>),
    Nil,
}

fn main() {
    use List::{Cons, Nil};
    let ls = Rc::new(Cons(1, Rc::new(Cons(2, Rc::new(Cons(3, Rc::new(Nil)))))));  // Rc::newで作成( カウント: 1
    println!("{:?}", ls);
    println!("{}", Rc::strong_count(&ls));

    let ls2 = Rc::new(Cons(3, Rc::clone(&ls)));  // 変数lsをクローンして複製 (カウント: 2
    println!("{:?}", ls2);
    println!("{}", Rc::strong_count(&ls));  // この時点でカウント2

    let ls3 = Rc::new(Cons(4, Rc::clone(&ls))); // 変数lsをクローンして複製 (カウント: 3
    println!("{:?}", ls3);
    println!("{}", Rc::strong_count(&ls));  // この時点でカウント3
}  // ここでブロックが終わるのでカウント0、破棄

/*
出力
Cons(1, Cons(2, Cons(3, Nil)))
1
Cons(3, Cons(1, Cons(2, Cons(3, Nil))))
2
Cons(4, Cons(1, Cons(2, Cons(3, Nil))))
3
*/

Boxはポインタだけど複数値を参照する機能は持っていないため、所有権が移った時点でRustの所有権の基本に沿ったシンプルなヒープとしての使い方が出来た。Rcを使用すれば複数参照できるヒープとして実装できる。

RefCell<T>

非常に理解に時間がかかった。 RefCellは T の値に対して実行時に可変参照を(強制的に)許可する機能を持つ。そのため、T が可変性を許可していなくてもRefCellの機能で可変参照を強制的に許可できる。テストなどで可変性のある値の中身を自由に入れ替えたいときなどに有効。

// 実装
trait List {
    fn append(&self, val: i32);
}

// ----------------------------------- TEST -----------------------------------

#[derive(Debug)]
struct MockList {
    values: Vec<i32>,
}

impl List for MockList {
    fn append(&self, val: i32) {
        self.values.push(val);  // ここが不変で借用されているのでエラー
    }
}

impl MockList {
    fn new() -> MockList {
        MockList { values: vec![] }
    }
}

// ----------------------------------------------------------------------------

fn main() {
    let ls = MockList::new();
    ls.append(1);
    println!("{:?}", ls);
}
// 実装
trait List {
    fn append(&self, val: i32);
}

// ----------------------------------- TEST -----------------------------------

#[derive(Debug)]
struct MockList {
    values: RefCell<Vec<i32>>,  // RefCell
}

impl List for MockList {
    fn append(&self, val: i32) {
        self.values.borrow_mut().push(val);  // borrow_mut()で強制的に可変借用できる
    }
}

impl MockList {
    fn new() -> MockList {
        MockList {
            values: RefCell::new(vec![]),
        }
    }
}

// ----------------------------------------------------------------------------

fn main() {
    let ls = MockList::new();  // 作った時点では不変
    ls.append(1);  // appendできる
    println!("{:?}", ls);
}

trait List が実際の実装なのでここをテストのために可変参照を許可するようにしたくない。こうしたときに強制的に可変参照を許可できるRefCellを使うことで自由に中身を入れ替えるモックを作ることができる。

Mutex<T>・Arc<T>

Mutexはスレッドセーフな可変参照を可能にする。また、Arc<T>はMutex同様スレッドセーフに複数参照を可能にする。すなわち、MutexとArcはそれぞれRefCellとRcのスレッドセーフ版という感じ。
また、Mutexはlock()メソッドが実装されている。これを呼ぶことで排他制御を保証するためにロックの有無をLockResultとして返す。

スマートポインタはまだ種類があるみたいだけどひとまず以上。

つぎはtraitの動的ディスパッチャと静的ディスパッチャについてまとめておきたい(ちょっと勉強したけどやっぱ忘れた)

Vinpok社 Taptekのよかったところ・微妙だったところ(プログラミング編)

こちらで衝動買い www.makuake.com

2019年4月下旬購入、2019年6月19日商品到着

というような感じでまだ完全に理解した状態じゃないけどひとまず数時間触ってみた感想

よかったところ

  • 膝の上にのせたときの安定感がよい

    • ゴムが良い安定感をだしている
  • 音がきもちよい

    • パチっ、カチっというような音。個人的にすき
  • LEDのパターンが多い(見て飽きない)

    • いちばんすきなのは押した箇所から波上にLEDが広がるように光るパターン
  • 掃除が楽そう

    • スイッチがしきつまっているので刷毛を使うだけできれいになりそう
  • 有線と無線のハイブリッド

    • 用途を使い分けれそうで大変よい
  • MacBookの設定が正しく反映される

    • F1..F12キーをデフォルトにする設定が正しく反映されてた

    • ちなみに以前使用していたAnkerの安いBluetoothキーボードでは反映されなかった

  • バイスを3つまで登録できる

    • 会社と自宅で使用するのでいちいちセッティングしなくてよいので楽ちん

微妙だったところ

  • 右のShiftキーが小さい

    • 結構多様するのですこし残念
  • 押す力が意外といる

    • キーの押しごこちが、ちょっと悪い

      • 端っこを押すと最後まで押し切られない(カチッとならない)

      • 今までカチカチと軽快なタイピング音だったのに押しきれなくてスカッて音なる

  • キーの反応が早い

    • キーが「カチッ」となる前に反応する

    • 組み合わせるショートカットキーの場合、いろんなキーマップが反応してしまった

  • あまり不快にならないオリジナル青軸、とのことだったが音の大きさに関してはもとの青軸と変わらない気がする(個人的主観)

    • 音色は変わった(洗礼されたきれいな音になった)

まとめ

  • 全体的には良い評価といえる(点数をつけるなら、70点ぐらい)

  • 右のShiftキーが小さいことに関しては、キーマップをいじって上矢印キーをShiftキーにマッピングしたらよいのでそれで完結

  • 押す力に関しては筋トレで完結

  • キーの反応と音は正直どうしようもなさそう

ひとこと

ゲームのときの使用感もレビューしたい

追記

使用して2ヶ月位でバッテリーが死んでいることに気づいた。ソッコーで友人に譲って結局自作キーボードの道へと歩んだのであった

VimmerのためのMagnetショートカットキー

Vimmerならエディター以外もVimっぽくしたいよね...?

MacOSのPC所持者ならだいたい持っている「Magnet」

Windowsのような画面分割が出来るやつなのだが、初期のショートカットは指をたくさん動かさなきゃいけないので大変だった

そこでトラックパッドよりキーボードをたくさん操作する人向けのショートカットを考えました

f:id:nnsnico:20190129150201p:plain
magnet_keyboard

Control + shiftに加えて上の画像のように設定をしました

指を動かさないでいいだけでなく、キーの配置と分割される位置がマッチしているのでショートカットをすんなり覚える事ができます

ゴイスーなえっち本を読んだのでHaskellについてまとめた

Haskellメモ

すごいH本を読んだのでHaskellに関してメモしたことをそのまんまここに残しておく。違うところもあるかも...

基本的なこと(データ型など)については省略

すばらしい機能

パターンマッチ

  • 与えられた引数に対してパターンマッチを行える

例) フィボナッチ数を求める(パターンマッチver.)

fib :: Int -> Int
fib 0 = 1
fib 1 = 1
fib x = fib (x - 1) + fib (x - 2)

ガード

  • 与えられた引数に対して条件式を行える

例) フィボナッチ数(ガード文ver.)

fibG :: Int -> Int
fibG x
  | n == 0    -> 1
  | n == 1    -> 1
  | otherwise -> fibG (n - 1) + fibG (n - 2)

case .. of ...

  • 与えられた引数に対してパターンマッチと条件式を行える

例) フィボナッチ数(case of ver.)

fibC :: Int -> Int
fibC n = case n of
  0         -> 1
  1         -> 1
  _ | n > 1 -> fibC (n - 1) + fibC (n - 2)  {-- case ofは上から評価されるので本来ガード文はいらない? --}

Haskellはこのように文法は違うものの、同じ機能を持たせることができる。使い方は見やすさなどを考慮して使い分ける

特殊な式について

do

Monad値をつくるための式

let .. in

letで関数を、inで式を定義する式 どこにでも定義できる

例) リスト内包式

[let inc x = x + 1 in (inc 1)]  {-- [2] (xを引数にとり+1して返す関数に対して1を引数に適用する式をListに内包して返す) --}

where

変数や関数を定義された式に対して束縛することができる 使い方はlet .. inとさほど変わらないので関数の定義によって見やすさのために使い分けるべき

return

Monadを返す。CやJavaのようなプログラミング言語とは異なって結果の返り値や処理の抜け出しとしての使用法ではなく、正しく返されるべきMonadにラップされて値が返される

例) mainはIO ()が返るべき

main :: IO ()
main = do
  let a = return "hello"  {-- aの値はMonadである --}
  let b = "world"         {-- bの値はStringである --}
  a >>= print             {-- `>>=`の左辺が受け付ける引数はMonadのみ。print関数を呼び出したのでaはIOモナドとして関数に適用される --}
  print $ b               {-- print関数は文字として表せるもののみ引数にとる(Monadは引数にとれない) --}
  print $ a               {-- printはMonadを引数に取れないので構文エラーとなる --}

Functorとは?Applicativeとは?Monoid?Monad?ん?

これらをざっくりいうと、型が型を引数にもつ(型引数)もの。つまり型を持つことのできる型クラス

すごいH本がいうところの文脈付きの型

またそれらがもつ値をあらゆる形に変更・加工することのできるもの

例) Maybe型やList型([])はこれらすべてのインスタンスである Maybe IntInt型を持つMaybeという型 [Int]Int型を持つ[]という型

このような型を引数(型引数)に新しい型を作る型(型コンストラクタ)は下に示した機能をもつことができる

前提のお話

  • 文脈付き型は関数を適用する際に中身を直接触ることが出来ない(Maybe aに対してaを直接触れることができない)

  • 同様に、文脈付き関数もまた直接関数を使用することが出来ない(Maybe (a -> b)という関数はa -> bを直接適用することが出来ない)

Functor

文脈付き型に対して関数を適用することのできるもの Haskellではfmap(<$>)がFunctorに属する

例)

fmap (\x -> x + 1) (Just 1)  {-- Just 2 --}

(+1) <$> (Just 1)            {-- Just 2 --}

(+2) <$> Nothing             {-- Nothing(Maybeの仕様より、値のない`Nothing`が返る) --}

Applicative

文脈を持つ値と関数同士を適用することができるもの Haskellでは中置関数で<*>がある

例)

(Just (+3)) <*> (Just 4)  {-- Just 7 (与えられた引数に対して+3をする関数に4を与える) --}

Nothing <*> (Just 4)      {-- Nothing(適用される関数がないので`Nothing`) --}

(Just (+3)) <*> Nothing   {-- 逆も然り --}

Monoid

文脈付き型を結合することができるもの

例)

[1, 2, 3] `mappend` [4, 5, 6]             {-- [1, 2, 3, 4, 5, 6] --}

Just [1, 2, 3] `mappend` Just [4, 5, 6]   {-- Just [1, 2, 3, 4, 5, 6] (Maybeのインスタンスである場合、中身を結合することができる) --}

Monad

文脈付き型に対して文脈付き型を返すことができるもの

  • これまでのFunctor、Applicative、Monoidは振る舞いが違うものの、全て文脈付き型を授かり文脈付き型を返すことに関しては全部一緒である

    • つまりMonadはFunctorにもApplicativeにもMonoidにもなり得るもの??

Monadreturn>>=>>という関数を持つとすごいH本には書いてある

例)

return $ Just 3                   {-- Just 3 (returnはClangやJavaの`return文`とは異なり、Monadをそのまま返す`関数`である) --}

Just 3 >>= \x -> return $ x + 3   {-- Just 6 (`>>=`は左辺のモナドから結果だけを取り出し右辺の関数に適用した結果を新しいMonadとして返す) --}

Nothing >>= \x -> return $ x + 3  {-- Nothing (MaybeはMonadなので`>>=`を適用できる) --}

Just 3 >> Just 4                  {-- Just 4 (両方がJustの場合、右を評価する) --}

Nothing >> Just 4                 {-- Nothing (言わずもがな) --}

↑たちのルール(XX則)

Functor則

  • idでファンクター値を写した場合、ファンクター値が変化してはいけない

例)

fmap id (Just 3)  {-- Just 3 --}

fmap id [1 .. 5]  {-- [1, 2, 3, 4, 5] --}

fmap id Nothing   {-- Nothing --}
  • 「fとgの関数合成でファンクター値を写したもの」と「g、fと順番にファンクター値を写したもの」が等しいこと

    • fmap (f. g) = fmap f . fmap gであること

Applicative則

以下の式は等価である

(pureは純粋にその関数を返す関数)

  • pure f <*> x = fmap f x

  • pure id <*> v = v

  • pure (.) <*> u <*> v <*> w = u <*> (v <*> u)

  • pure f <*> pure x = pure (f x)

  • u <*> pure y = pure ($ y) <*> u

Monoid則

以下の式は等価である

  • mempty mappend x = x

    • 空のモノイド値に対してモノイド値を結合するとき、モノイド値が評価されること
  • x mappend mempty = x

    • モノイド値に対して空のモノイド値を結合するとき、モノイド値が評価されること
  • (x mappend y) mappend z = x mappend (y mappend z)

    • 3つのモノイド値を結合するとき、それぞれの結合する順番に関係なく結果が等しくあること

Monad

  • 左恒等則

    • returnを使ってデフォルトの値をデフォルトの文脈に入れたものを>>=を使って関数に食わせた結果は、単にその値にその関数を適用した結果と等しくあること

      • return x >>= ff xは等価である
  • 右恒等則

    • >>=を使ってモナド値を食わせた結果は、元のモナド値と不変である

      • Just 123 >>= returnJust 123
  • 結合法則

    • >>=を使ったモナド関数適用の連鎖があるときに、どの順序で評価しても結果は同じであるべき

    • (m >>= f) >>= gm >>= (\x -> f x >>= g)が同じである

      • fを先に評価しgを後に評価するような関数をモナド値に適用した結果とgを先に評価しfを後に評価する関数をモナド値に適用した結果は等価である

モナディック関数

モナディック関数とは

モナド値を操作したり、モナド値を返したりする関数(両方も可!)

すごいH本より

Listは文脈付き型であるためMonadであり、Monad値を操作できる関数(map、filter...)はモナディック関数である

関数の紹介

MonadはApplicative Functorであり、Applicative FunctorはFunctorである

Monad > Applicative > Functror

  • liftM

    • fmapの強化版?

      • fmap -> 関数をFuntorに適用できる関数である

      • liftM -> 関数をMonadに適用できる関数である

        • 上の定義に伴ってMonadのほうが扱える範囲が広い
  • ap

    • <*>の強化版?

      • <*> -> Applicativeの関数と値同士を適用できる

      • ap -> Monadの関数と値同士を適用できる

  • liftA2

    • 関数を2つのアプリカティブ値に適用できる
  • liftM2, liftM3 ...

  • join

    • モナド値が入れ子になっている部分を潰して平らにする

    • Scalaでいうところのflatten, flatMapに若干似ている

以上だぁ
なんとなくモナドについての理解が深まったのでcats on Scalaでより理解を深めたいっすね

Alfredとかでキーバインドを⌘+Spaceとしたときに英数も一緒に送信しちゃう

タイトルママ。

僕は普段Alfredのキーバインドを⌘+Spaceにしています。
基本的にAlfredで検索する内容は英語ばかりなので、起動したときはすぐに英数の状態になっていてほしいですね。
素早い操作に慣れてなにも確認せずに起動した瞬間にタイピングして「かな」だったときはとても苛立ちが...ピキィ!!

Karabiner-Elementsで解決

いつもどおりこういうバインディング的な作業はKarabiner-Elementsにお願いしてます。
今回は⌘+Spaceのキーバインドに合わせて英数が送信される設定に加えてCtrl+Spaceもついでに加えたルールファイルを作成しました。

{
  "title": "Alfred用ルール",
  "rules": [
    {
      "description": "Command + Spaceで起動時に英数キーを送信する(Alfred用)",
      "manipulators": [
        {
          "type": "basic",
          "from": {
            "key_code": "spacebar",
            "modifiers": {
              "mandatory": [
                "command"
              ]
            }
          },
          "to": [
            {
              "key_code": "spacebar",
              "modifiers": [ 
                "command"
              ]
            },
            {
              "key_code": "japanese_eisuu"
            }
          ]
        }
      ]
    },
    {
      "description": "Control + Spaceで起動時に英数キーを送信する(Alfred用)",
      "manipulators": [
        {
          "type": "basic",
          "from": {
            "key_code": "spacebar",
            "modifiers": {
              "mandatory": [
                "control"
              ]
            }
          },
          "to": [
            {
              "key_code": "spacebar",
              "modifiers": [ 
                "control"
              ]
            },
            {
              "key_code": "japanese_eisuu"
            }
          ]
        }
      ]
    }
  ]
}

これを~/.config/karabiner/assets/complex_modifications配下に好きな名前でjsonファイルとして保存しておくと勝手に追加されてます。

f:id:nnsnico:20180907013114p:plain

いまさらReact + Reduxのセットアップをおさらいする

研究をろくにやらないでいるnnsです。

いろんなところでReactやReactNativeをさわる機会が多いものの覚えが悪いのでReact + ReduxのSPAプロジェクトの作成手順を毎回忘れます。

忘れないように自分なりに手順を書きます。あくまで手順メモなのでReactやReduxについての説明はほんのちょっぴりだけです。

1. Node.jsを入れる

そのまんま。バージョンはlatestを入れたほうがいいかも

2. create-react-appをグローバルでインストールする

npmを使用してReactプロジェクトをさらっと作ってくれるパッケージを入れます。

$ npm i -g create-react-app

-gオプションを加えることでグローバル環境下にパッケージを入れることができます。

3. create-react-appコマンドでReactプロジェクト作成

先ほど入れたパッケージを利用してプロジェクトを作成します。
コマンド名に続いてプロジェクト名を入力します。今回はsample-react-appにしました。

$ create-react-app sample-react-app

一応起動確認。勝手にブラウザにページが表示されると思います。

$ npm start

これでReactアプリケーションは作成されました。続いてReact-Reduxの環境を作ります。今回は最低限の環境を作るので数字のインクリメント・デクリメントをReduxで管理するアプリケーションを作成します。

4. Redux環境のインストール

作成したプロジェクトに対して新たに次のパッケージをインストールします。オプションに-S、あるいは--saveを入れることでプロジェクト環境にパッケージをインストールすることができます。

$ npm i -S react-redux redux

これでreduxに必要な2つのパッケージがインストールされました。

5. reducerの作成

依存関係のないものから作成するのがセオリーなのでreducerから作成します。
今回、管理したいstateは表示される数字、アクションはそれに対するデクリメント、インクリメントなのでそれらの実装をsrc/reducers/index.js配下に書いていきます。

5-1. Stateの初期状態の定義

すべてのStateは初期状態を持っている必要がありますのでこれを定義します。今回の場合、Stateである数字は0を初期値とします。

const initialState = 0
5-2. 状態を変更する関数を作成する

reducerは受け取ったアクションに対して新しい状態を返す役割を持ちます。今回の場合、デクリメント、あるいはインクリメントというアクションに対して状態である数字が変わるので、numという関数にします。
ちなみに、データフローにしたがって、初期起動時に必ずreducerは通るのでswitch文にdefaultを入れるのを忘れずにします。

function num(state = initialState, action) {
  switch(action.type) {
    case 'DECREMENT': {
      return state - 1;
    }
    case 'INCREMENT': {
      return state + 1;
    }
    default: {
      return state;
    }
  }
}

export default num;

6. Actionの作成

actionの役割はcomponentとreducerの橋渡し的なものです。component側から呼び出されたactionのタイミングに合わせてreducerが状態を変更してくれるという流れです。
実際のコードです。src/actions/index.js配下に書いていきます。

// action types
const DECREMENT = 'DECREMENT';

const INCREMENT = 'INCREMENT';

// action creators
function decrement() {
  return {
    type: DECREMENT,
  };
}

fucntion increment() {
  return {
    type: INCREMENT,
  };
}

actionにはreducer側でどのアクションが呼び出されたかを識別するためのActionTypeとcomponent側で呼び出すために使用するActionCreatorに分けられます。
変更されるStateに対して追加の情報を与えたいときはActionCreatorの関数に対して引数で渡します。そしてreturn文の中のオブジェクトに新しくその値をプロパティと添えて入れてあげるだけです。

7. Componentの作成

React-ReduxのComponentには大きく分けてContainer ComponentとPresentational Componentの2つがあります。
Container Componentから先に作ります。

7-1. Container Componentの作成

Container Componentはデータやコールバック関数などといったビジネスロジックをもったコンポーネントです。ですので実際の描画とはあまり関わることがほとんどありません。Stateを各Componentが持つPropsに変換するのもここで行います。 /src/container/AppContainer.jsに記述。/App.jsを一部書き換えます。

import React from 'react';
import { connect } from 'react-redux';

import App from '../component/App'
import logo from '../logo.svg';
import '../App.css';

class AppContainer extends React.Component {
  constructor(props) {
    super(props);
    this.decrement = this.decrement.bind(this);
    this.increment = this.increment.bind(this);
  }

  decrement() {
    alert('デクリメント');
  }

  increment() {
    alert('インクリメント');
  }

  render() {
    const { num } = this.props;
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
        <div>
          <App num={num} decrement={this.decrement} increment={this.increment} />
        </div>
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    num: state,
  };
}

export default connect(mapStateToProps)(AppContainer);

decrement()increment()は状態を変更するためのコールバック関数です。propsとしてComponentに渡すことでComponentのイベントリスナーに応じて反応します。
mapStateToProps()は関数名の通り、reduer(store)で管理しているStateをComponentで扱えるようにpropsとして変換しています。connect()はそのヒモ付を行ってくれる関数です。このファイルを呼び出すときにconnectされたものをデフォルトとしてインポートしてほしいのでconnectをexport defaultしています。

7-2. Presentational Componentの作成

Presentational Componentは描画のみを行うComponentです。ボタンを押したときの処理は後に記述するContainer Componentが担当するので、Presentational Componentはpropsから預かったコールバック関数(decrement()increment())を呼び出すだけです。
src/component/App.jsに記述します。

import React from 'react';

class App extends React.Component {
  render() {
    const { num, decrement, increment } = this.props;
    return (
      <div>
        <button onClick={() => decrement()}> - </button>
        <button onClick={() => increment()}> + </button>
        <div>{num}です</div>
      </div>
    );
  }
}

8. StoreをContainer Componentに注入

最後に、状態を持つreducer(Store)をContainer ComponentであるAppContainerに注入します。
/index.jsを以下のように変更

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';

import './index.css';
import App from './App';
import AppContainer from './container/AppContainer'
import registerServiceWorker from './registerServiceWorker';
import reducers from './reducers/'

const store = createStore(reducers);

ReactDOM.render(
  <Provider store={store}>
    <AppContainer />
  </Provider>, 
  document.getElementById('root'),
);
registerServiceWorker();

createStore()の引数にreducerを代入することでstoreとして作成することができます。そしてContainer ComponentをProviderでラップ、storeというpropsにcreateStore()で作成したstoreを指定あげれば準備OK

9. Stateを変更できるかの確認

ここまでで一度起動すると、ボタン2コと「0です」というテキストが新たに作成された画面ができます。ボタンを押すとアラートが出るのみです。
ここでContainer Componentのコールバック関数内の内容を書き換えて実際にStateを変更します。
/src/container/AppContainer.jsを以下に変更

import { decrement, increment } from '../actions/'

....

  decrement() {
    const { dispatch } = this.props;
    dispatch(decrement());
  }

  increment() {
    const { dispatch } = this.props;
    dispatch(increment());
  }

....

Providerでラップされたコンポーネントにはdispatch()という関数が備わっています。これにActionCreatorを引数に与えてあげることでアクションがアタッチされ情報がreducerに送られます。

もう一度起動。無事インクリメント、デクリメントができました。

個人的にはこれに対してTypeScriptを導入したりすると、型の恩恵によりストレスフリーな開発ができるのでおすすめです。おしまい

Karabiner-Elementのプラグイン「Vim-emulation」でVivaldiを無視するルールを追加する

前フリ

前回の続きのお話です。
もっといろんなアプリをVim化したいという願望をもっていた僕でしたが、結局KaraBiner-Elementの「Vim-emulation」というプラグインを入れることで落ち着きました。

いろんなアプリをVim化する上でESCキーがアプリと競合して「今どっちのESCキーが反応したの?」とわちゃわちゃするのがとっても嫌だったのですが、Vim-emulationを使用する場合、「ctrl + [」キーのみでインサートモードを解除することで解決しました。(まだ慣れていませんが)

本題

SurfingKeysと競合しあう問題はVim-elementsの設定ファイルをいじることで一部のアプリに対して適用を無視することができます。
Chrome、iTermなど基本的なアプリは標準の設定で無視されています。ありがたい。

僕が普段使っているVivaldiは設定されてないので、自分で入力する必要があります。
しかしながらこの「Vim-emulation」、設定ファイルの行数が何十万行にも渡る巨大なファイルになっているのでこれを見て手入力するのはとても疲れます。(途中までやってしんどかた)

絶対にもっとイケてる方法はあるんやろなあとか思いながら自分でスクリプト書きました。 Python初心者なのでコードの汚さはご愛嬌

import json

add_name_arr = [
    "^com\\.vivaldi\\.Vivaldi$",
]

json_data = {}

with open("~/.config/karabiner/assets/complex_modifications/{設定ファイル.json}", "r") as res:
    json_data = json.load(res)

with open("~/.config/karabiner/assets/complex_modifications/{設定ファイル.json}" "w") as res:
    for i in range(len(json_data['rules'])):
        manipulators_ary = json_data['rules'][i]['manipulators']
        for j in range(len(manipulators_ary)):
            manipulators_obj = manipulators_ary[j]
            # "conditions"キー、"type"、"bundle_identifiers"を追加
            if 'conditions' not in manipulators_obj:
                print("conditions not exists")
                manipulators_obj.update({"conditions": [{"type": "frontmost_application_unless", "bundle_identifiers": []}]})
            bundle_identifiers = manipulators_obj['conditions'][0]["bundle_identifiers"]
            # 追加しようとしている要素がなければ"bundle_identifiers"に追加
            for add_name in add_name_arr:
                # ここをいじればキーを削除するスクリプトに変えれる
                if (add_name not in bundle_identifiers):
                    bundle_identifiers.append(add_name)
    print(json.dumps(json_data, indent = 2))
    # エンコード(書き込みモードなのでそのまま上書き)
    json.dump(json_data, res, indent = 2)

エラーなくvivaldiが追加されたjsonが出力されたら成功です。
add_name内のアドレスを変更することで他のアプリもルールに追加することができます。
設定ファイルはすべてのプラグインにおいて同じフォーマットなので、もしかしたら「Vim-emulation」に限らずとも使用できるかもしれないです。(試してない)

コードの全体は僕のdotfilesにあります

github.com

追記

jsonは正しく出力されると思いますが追加したプラグインが既に有効化されている場合、設定が正しく反映されないのでComplex Modificationsタブから対象のプラグインをRemoveした上で再度有効化してください。