Pixel Pedals of Tomakomai

北海道苫小牧市出身の初老の日常

Re: 不良セクタの隣〜 横へな 2014.3.7 問題

不良セクタの隣 の問題で肩慣らし。

以下はとりあえずテスト通しただけの状態そのままのコード。単体テスト含めてフルスクラッチからで45分くらい。場当たり的にモジュール化したので、無駄が多い。

初め「複数の」を見落としてて、最後に方針転換したけど、適度にモジュール化されてたのでなんとかなった。

Cloud9上で解いたので、キーバインドでも苦しんだ。Ctrl-s 押し忘れてセーブされてなかったり Ctrl-k 押してよくわからなくなったり。あと、45分の時間には含んでないけど、 コアモジュールのインストールも必要

package Sector;
use strict;
use warnings;
use Exporter qw(import);

our @EXPORT_OK = qw(solve);

my @all_sectors = (
    [100 .. 107],
    [200 .. 215],
    [300 .. 323],
    [400 .. 431],
);

sub degrees ($$) {
    my ($sectors, $sector) = @_;
    my $deg = 360 / @$sectors;
    my $sec_num = $sector - $sectors->[0];
    if ($sec_num == 0) {
        ([360 - $deg / 2, 360], [0, $deg / 2]);
    } else {
        ([($sec_num - .5) * $deg, ($sec_num + .5) * $deg]);
    }
}

sub sectors_in_degrees ($$$) {
    my ($sectors, $deg1, $deg2) = @_;
    my %result;
    for my $sec (@$sectors) {
        my @ds = degrees($sectors, $sec);
        for (@ds) {
            my ($d1, $d2) = @$_;
            $result{$sec}++ unless ($d1 <= $deg1 && $d2 <= $deg1) || ($deg2 <= $d1 && $deg2 <= $d2);
        }
    }
    return keys %result;
}

sub warning_sectors ($$) {
    my ($all_sectors, $sector) = @_;
    my $ringnum = int($sector / 100) - 1;
    my @degrees = degrees($all_sectors->[$ringnum], $sector);

    my %result;
    
    my $localnum = $sector % 100;
    my $localmax = @{$all_sectors->[$ringnum]};
    $result{$all_sectors->[$ringnum][($localnum + 1) % $localmax]}++;
    $result{$all_sectors->[$ringnum][($localnum + $localmax - 1) % $localmax]}++;

    if (0 < $ringnum) {
        my @secs = map { sectors_in_degrees($all_sectors->[$ringnum - 1], $_->[0], $_->[1]) } @degrees;
        $result{$_}++ for @secs;
    }
    if ($ringnum < $#$all_sectors) {
        my @secs = map { sectors_in_degrees($all_sectors->[$ringnum + 1], $_->[0], $_->[1]) } @degrees;
        $result{$_}++ for @secs;
    }
    
    keys %result;
}

sub _diff ($$) {
    my ($ar1, $ar2) = @_;
    my %ar2 = map { $_ => 1 } @$ar2;
    grep { ! $ar2{$_} } @$ar1;
}

sub _uniq ($) {
    my $ar = shift;
    my %ar = map { $_ => 1} @$ar;
    keys %ar;
}

sub solve ($) {
    my @broken = split /,/, $_[0];
    my %warnings;
    for (map { warning_sectors(\@all_sectors, $_) } @broken) {
        $warnings{$_}++;
    }
    my @many_warnings = grep { $warnings{$_} >= 2} keys %warnings;
    my @pure_warnings = _uniq [_diff(\@many_warnings, \@broken)];
    join ',', sort @pure_warnings or 'none';
}
use strict;
use warnings;
use Test::More import => [qw(done_testing is)];
use Sector qw(solve);

while (<DATA>) {
    tr/\r\n//d;
    my ($num, $in, $out) = split /\s+/, $_;
    is solve($in), $out, "TEST#$num";
}

done_testing;
__END__
0  400,401,302 300,301,402
1  105,100,306,414 none
2  100 none
3  211 none
4  317 none
5  414 none
6  100,106 107
7  205,203 102,204
8  303,305 304
9  407,409 306,408
10 104,103 207
11 204,203 102,305
12 313,314 209,418
13 419,418 314
14 100,102,101 201,203
15 103,206,309 205,207,308,310
16 414,310,309 206,311,413
17 104,102,206,307,102,202 101,103,203,204,205,207,308
18 104,206,308,409,407 103,205,207,306,307,309,408,410
19 313,406,213,301,409,422,412,102,428 none
20 101,300,210,308,423,321,403,408,415 none
21 304,316,307,207,427,402,107,431,412,418,424 none
22 205,408,210,215,425,302,311,400,428,412 none
23 200,311,306,412,403,318,427,105,420 none
24 105,305,407,408,309,208,427 104,209,306,406
25 311,304,322,404,429,305,316 203,303,321,405,406,430
26 210,401,316,425,101 211,315
27 414,403,404,416,428,421 303,415
28 207,300,103,211,428 104,206
29 322,314,310 none
30 427,200,215 100,323
31 311,402,424,307,318,430,323,305,201 200,204,301,302,306,322,423,425,431
32 425,430,408 none
33 202,320,209,426 319,427
34 430,209,302,310,304,431,320 202,303,323
35 208,206,406,424,213,312 207,311,313
36 420,302,313,413,317,402 301,403
37 319,306,309,418,204,411 305,307,308,412
38 400,308,105,430,203,428,209 104,210,429,431
39 200,305,214 215
40 214,408,410,407,317,422 306,316,409,423

毎回そうなんだけど、実装中、部品の単体テストをしてないので、最後にテスト全部通るかは神のみぞ知る。とはいえ、1時間で部品の単体テストまで書くのは、時間配分的に現実的ではないと思う。

追記: 3年前の自分の回答 。今書いたコードより整ってるようには見えるけど、 $D ってなんだっけ・・・。

GHCi上でpiと打てば円周率が表示されるという話

裏書きに残りっぱなしになってたのを書いておく。GHCI上で pi と打つと、πの値が表示できる。

Prelude> pi
3.141592653589793

Pythonだとそうはいかない。

>>> pi
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'pi' is not defined
>>> from math import pi
>>> pi
3.141592653589793

つまり、Haskellではグローバルな名前空間pi が出ているように見えるということ。これはなかなか気持ち悪い。

pi の正体を見てみよう。

Prelude> :i pi
class Fractional a => Floating a where
  pi :: a
  ...
        -- Defined in ‘GHC.Float’

Floating 型クラスに定義されているようだ。 Floating 型クラスは Prelude モジュールに含まれているので、 import などしなくても名前にアクセスできる。なるほど。

さて、拙著 Haskell入門 にも書いたが、この型クラスは浮動小数点数を意味する。この型クラスには pi 以外に、一般的な数値計算で必要な explogsin などの関数も入っている。代表的なインスタンスDoubleFloat

Prelude> :i Floating
class Fractional a => Floating a where
  pi :: a
  exp :: a -> a
  log :: a -> a
  sqrt :: a -> a
  (**) :: a -> a -> a
  logBase :: a -> a -> a
  sin :: a -> a
  cos :: a -> a
  tan :: a -> a
  asin :: a -> a
  acos :: a -> a
  atan :: a -> a
  sinh :: a -> a
  cosh :: a -> a
  tanh :: a -> a
  asinh :: a -> a
  acosh :: a -> a
  atanh :: a -> a
  GHC.Float.log1p :: a -> a
  GHC.Float.expm1 :: a -> a
  GHC.Float.log1pexp :: a -> a
  GHC.Float.log1mexp :: a -> a
  {-# MINIMAL pi, exp, log, sin, cos, asin, acos, atan, sinh, cosh,
              asinh, acosh, atanh #-}
        -- Defined in ‘GHC.Float’
instance Floating Float -- Defined in ‘GHC.Float’
instance Floating Double -- Defined in ‘GHC.Float’

pi が定数ではなく型クラスのメソッドになっているのは、恐らく FloatDouble で多相的に扱いたいからであろう。 GHCの実際の定義 は、以下。お、おう、といった感想。浮動小数点数だから、リテラルに小数点を何桁まで書いたかは精度とは関係ないってことだろう。結局は親の型クラスが持つ fromRational を使って処理される。

instance  Floating Float  where
    pi                  =  3.141592653589793238

instance  Floating Double  where
    pi                  =  3.141592653589793238

一応、ghci上で違いを見ておく。

Prelude> pi :: Double
3.141592653589793
Prelude> pi :: Float
3.1415927

もう一つ疑問が残るのは、数ある数値系の型クラスの中で、なぜ Floating というより具体性の高い型クラスに pi が定義されたのか。 Floating に定義されている関数は、実数値上に定義される関数である。Haskellでは、有理数Fractional 型クラスで表現されている。しかし、当然ながら実数値を正確に表現できる型はない。そこで、コンピュータが一般的に用いる浮動小数点数にこれらの関数を定義した、ということだろう。

最後にまとめると、 pi については以下となる。

  • Prelude に定義されているので、識別子 pi でアクセスできる
  • メソッドになっているため、 FloatDouble で多相的に扱える
  • 実数という型がないので、浮動小数点数上の演算としているのだろう

自分の開発環境用Vagrantfileを作った

qiita.com

ubuntuのインストール作業に勤しむ意味はないので、vagrantに任せることに。

ということでWindows上でvagrant使うことに決めたのだけど、Surface StudioとSurface Book 2の両方で環境構築するのはダルいので Vagrantfile 作って上げた。

github.com

最近はデフォルト厨なので Vagrantfile なんて要らんかなと思ったのだけど、細かい調整でハマって時間を潰してしまったりしたので、まとめることにした。細かい点とは、例えば以下の通り。

  • stackapt で入れない (コマンドを覚えられないのでググるのがめんどい)
  • init.elintero の設定をググらないと書けない
  • libtinfo-dev 入れないと intero が動かない
  • LC_ALL 指定しないと shell が日本語を受け付けない
  • .tmux.conf を適切に設定しないとキーバインドで俺が死ぬ
  • その他、今は忘れている暗黙知をこのリポジトリに集めて二度と同じハマり方をしないようにする

Windows 用にしているけど、OS Xでも使えるはず。とはいえ、OS X上ならVM使わずにローカルに開発環境作る気がする。

WindowsのreaderアプリがEdgeに惨殺される

Windowsreaderアプリが2/15で使えなくなるとのこと 。騒いでいる人がほとんどいないけど、Surfaceタブレットモードで使ったときの相性が非常に良かったので、どうしてそんなことをするのか全く理解ができない1。これでSurfaceを使う理由が1つなくなってしまった。

2/15までサポートされるということになっているが、readerアプリを立ち上げると画面上部がメッセージで専有されてUIがぶっ壊れるので、もうすでに使い物にならない。スクリーンショット取るのが億劫だったのでTwitterから拝借。

が、代替を探したところ、幸い Pico Viewer が要件を満たしてくれることがわかった。使用頻度が高かったサムネイルを一覧するビューがないのだけは残念だが、それ以外のタブレットモードの閲覧に関しては reader とほぼ同じ使い勝手、いや、それ以上使い勝手なので、十分満足できる。価格も財布に優しい。もし、代替品に困っている人が居たら試してみて欲しい。


  1. Edge使わせるため、というのは明白だけど、思考が短絡的過ぎる。

Haskell入門の10章をDocker化する

Haskell入門 の10章は、 SQLite への依存があったりして Windows で試すのは若干面倒だったので、 Docker for Windows で試せるようにした。

https://github.com/hiratara/Haskell-Nyumon-Sample/compare/docker/chap10

docker/chap10 ブランチを持ってきて、Docker for Windows が動いている環境でこんな感じで動かせる。

$ docker-compose build
$ docker-compose run --rm --service-ports weight-recorder

# ソースをいじって stack build したいとき
$ docker-compose run --rm weight-recorder build weight-recorder

docker hubに stack dockerコマンド用のイメージがある ので、LTSが一致しているものを持ってきてベースイメージにしている。なお、残念ながら stack dockerコマンドはWindows非対応 なので今回の目的には使えない。

Windowsで作業ディレクトリを単純にバインドマインティングすると、

Installing executable(s) in
/work/.stack-work/install/x86_64-linux/lts-8.24/8.0.2/bin
/work/.stack-work/install/x86_64-linux/lts-8.24/8.0.2/bin/.copyFile5117023052084420925.tmp:
copyFile: hardware fault (Input/output error)
Completed 2 action(s).

のように微妙なエラーが出たりすることがあるので、 docker-compose でデータボリュームを作ったりしている。後、何も考えずに Docker 化すると、docker-compose build 時の stack の初期化が時間がかかりすぎてあまりにも辛いので、キャッシュが働くように COPY 前にある程度パッケージをビルドするようにしてたりする。

後、かんたんのためにDBを作業ディレクトリに置いていたのがきつくなったので、軽く手を入れて環境変数から指定できるようにした。 /data 以下にDBを置いている。

Surface Book 2 15” を買った

去年 と同様に、今年は Surface Book 2 15”個人輸入した。 MS製品の個人輸入は3度目 1 で、毎年年末の散財の恒例行事となりつつある。

誤解のないように書いておくと、Surface Book 2は 国内でも販売している 。ただし、 15” はUSのみでの販売であるのと、US配列も国内では手に入らない。

15” は フルパワーだと電源につないでいてもバッテリーが減る という問題はあるものの、実用上そんなに困ってはいない。ゲーミングでむしろ邪魔になるのは高温でパワーが抑制されてしまう方で、これは結構頻繁に遭遇する。ので、ゲーミングに使うときは設定は低めの設定で使っている。PUBGも設定さえきちんとすれば快適に遊べる。

f:id:hiratara:20171211085147j:plain

今回のSurface Book 2の事前予約で、MSはいろいろとしくじっている。 redditでは事前予約したのに来ないという悲痛な叫び が多数投稿されている。キャンセルも受け付けてくれず、発送されたとしてもマイクロソフトからは今回の注文に関して何もメールが送られてきていない。お金だけ支払って本体が消息不明になったという人まで出ている。

今回、自分もこの騒動に巻き込まれており、こちらの場合はまだ支払いを完了できていない。MSのサポートに支払いを終わらせるように何度もお願いしているのに、自分の英語力が足りないせいなのか、未だに精算を完了してもらえていない。このままだとオーソリの有効期限が来て、無料でSurface Book 2を手に入れてしまうことになりそうだ。

なお、今回も転送には 1worldshopping を利用した。何度も高額の品物を依頼しているが、今のところ事故ったことはない。サポートも、日本時間に日本語の窓口へメールすれば、きちんと日本語で返ってくる。DHLの配送ログは以下のようになった。最終的には佐川急便が11/25の夕方に、届けてくれている。

Saturday, November 25, 2017 Location    Time    Piece
18  Delivered - Signed for by : DLVD BY AGNT    KAWASAKI    14:54
17  Forwarded for delivery  YOKOHAMA - JAPAN    08:09

Friday, November 24, 2017   Location    Time    Piece
16  Forwarded for delivery  YOKOHAMA - JAPAN    14:04   
15  Arrived at Delivery Facility in YOKOHAMA - JAPAN    YOKOHAMA - JAPAN    12:37
14  Departed Facility in TOKYO - JAPAN  TOKYO - JAPAN   11:57
13  Processed at TOKYO - JAPAN  TOKYO - JAPAN   11:55
12  Clearance processing complete at TOKYO - JAPAN  TOKYO - JAPAN   11:22
11  Arrived at Sort Facility TOKYO - JAPAN  TOKYO - JAPAN   11:03
10  Customs status updated  TOKYO - JAPAN   09:26   
9   Transferred through NARITA - JAPAN  NARITA - JAPAN  09:25

Thursday, November 23, 2017 Location    Time    Piece
8   Departed Facility in CINCINNATI HUB - USA   CINCINNATI HUB, OH - USA    04:54
7   Processed at CINCINNATI HUB - USA   CINCINNATI HUB, OH - USA    03:48

Wednesday, November 22, 2017    Location    Time    Piece
6   Processed at CINCINNATI HUB - USA   CINCINNATI HUB, OH - USA    10:56
5   Shipment on hold    CINCINNATI HUB, OH - USA    06:37
4   Arrived at Sort Facility CINCINNATI HUB - USA   CINCINNATI HUB, OH - USA    01:25

Tuesday, November 21, 2017  Location    Time    Piece
3   Departed Facility in WEST PHILADELPHIA - USA    WEST PHILADELPHIA, PA - USA 22:26
2   Processed at WEST PHILADELPHIA - USA    WEST PHILADELPHIA, PA - USA 22:23
1   Shipment picked up  WEST PHILADELPHIA, PA - USA 15:14

  1. 最初に買ったSurface Pro 3は国内で買った。

今日は「Club MySQL #2:(MySQLの)XProtocolはじめました、Haskellで」の日です

マニアックなイベント に来てますので、メモを残しています。

XProtocol始めました、Haskellで / Naoto Ogawaさん

  • 意外とHaskellの人が多いかな、と
  • haskellMySQLで半分半分
  • XProtocol
    • ProtocolBuffer
    • Xはクロス (いろいろな言語から)
    • CRUDスタイルAPIもある
    • ドキュメントストアとの親和性
    • パイプライン処理(これに注目したい)
  • XDev API
    • EBNFの定義がある
    • BNFとは? → 文法を定義したもの
    • 複数DBサーバのコネクション管理も含む(理解しきれてないけど)
  • XPluginをMySQLへインストールする
    • Xdev API経由でユーザプログラムが利用
  • world_x データベースをサンプルとしてインストールしておくと良い
    • doc_id があるテーブルがドキュメントストアとして扱われる
    • _iddoc 内のJSONのものとも一致させる
    • _idGENERATED だけど自動に作ってくれるわけではない。アプリが入れる
  • mysqlx.so を入れる
  • mysqlsh
    • 3306 ではなく 33060 を使う(スライドではミスって 33061 だけど)
    • プロトコルを覗くプロクシを作ったためミスった
    • mysql-js> というプロトコルで、JSのコードを実行できる
    • find("$.GNP = 828")$ はルートのイメージ
    • *ワイルドカードが使えたり
  • XProtocolのドライバが文字列の式を解釈して、XProtocolにしてあげなければならない
    • 昔のドライバは、サーバ側でSQLをパースしている
  • XProtocolとして生のSQLを投げることは可能
    • .find とかを使って、一部だけをSQLにするとかはダメ
  • 様々な知識が必要だが、今日は「XProtocolの仕様」と「ProtocolBufferの理解」
    • 課題: 名前の衝突、TLSの難しさ、パーサライブラリの選択など → 作り直しかも
  • .proto ファイルにも仕様が書かれているので、読んだほうがいい
  • .proto ファイルから、ツールを使って各言語のオブジェクトを生成する
  • XProtocol
    • メッセージ長、タイプ、ペイロード(protobuf)、の繰り返し
    • 全体のメッセージ長がない
    • 全体のメッセージ長が欲しいのは、実装上のチョイス。ストリーミング処理すれば不要かも
    • メッセージ長はリトルエンディアン
    • 例えば ClientMessages のタイプ 19CRUD_UPDATE
    • EXPECT_OPENEXPECT_CLOSE はパイプライン処理用
    • ServerMessages で、 RESULTSET_FETCH_DONE_MORE_RESULTSETS が来たら、フェッチの残りがあるということ
  • Find メッセージ
    • collection スキーマやテーブル
    • criteria WHERE句
    • args バインド
    • grouping_criteria having句
    • 17 CRUD_FIND
  • protobuf は、フィールド名は送っていない。数字のタグのみ
    • protoファイルに定義されている

本当はこわいMySQLプロトコル / tmtmsさん

  • RubyMySQL X Protocol 作ってたけど、今日は古いプロトコルの話
  • 参照系: フィールド数でループ。レコードはEOFまで
  • クライアントはクエリが更新系か参照系かは知ってない
    • サーバから戻ってくるフィールド数を見て、判断する
  • LOAD DATA LOCAL INFILE
    • クエリをサーバが解釈。ファイル名をサーバに教えてもらう(!)
    • Proxyでサーバ名を書き換えることができる!
    • Proxyはクエリを LOAD DATA LOCAL INFILE に書き換えることができる(!!!)
  • 対策
    • SSL接続
    • クライアント側で LOCAL INFILE を無効化

XProtocol始めました、Haskellで(後半) / Naoto Ogawaさん

  • 結果セット Row メッセージ
  • Expr で表現
    • LITERAL Scalar V_SINT
  • ProtocolBufferのzigzag encoding
    • -99197 となる
  • 関数はドライバが文字列をパースして XProtocol の表現に
    • 構文解析の知識が必要
    • SQLで利用される関数すべてが、XDevAPIでサポートされているとは限らない
    • 関数名を XXX などとした場合は、サーバ側がエラーとする
    • SUM(DISTINCT hoge) とか 'a' not_regex 'aaa' とかできなかったり
  • パイプライン
  • エラー処理
    • Error メッセージとして却ってくる
    • protoファイル側に書いてある
  • XProtocolの注意
    • ObjectとErrorが2箇所くらいある
    • protoファイルごとに名前空間を変えてみては?
  • ドライバの設計
    • 型の整合性とか
    • 正常であればメッセージがあるケースとか
    • ドライバのレイヤの厚さは?
    • 依存を少なくしたいとか
  • haskellのライブラリ
    • XDev APIのEBNFには従ってない
    • XProtocolっが正しく吐ければいい
  • 展望
    • 交渉、ストリーミング、データ型、結果セット分割、などなど
  • MySQL5.7で試している
    • bindの謎の文字列は、文字列じゃなくていいでしょ
  • RubyでのXProtocolの実装を再開しようかな」
  • このプロトコルはGA?? わからず
  • プロトコルオタク的には楽しいけど、一般人の用途は・・・?

この会について

  • いつもは短い話を聞く会
  • 長くじっくり聞く会として、この会を開いている
  • また来てください