Rust (5)

台所のガスレンジで3口ある所のうち一つが点火しなくなった。 ノブを回しても、火花が飛ばない。後の2口は問題無しと言う主訴です。 オイラーの診断では、レンジが壊れたな、ですな。。。

着火マンとかで火をつけようにも、直ぐに自己消火。安全装置が内蔵されてんのか。注意一秒、 事故一生(これって、交通安全標語)ですから、不注意をカバーしてくれるのは、正しい科学 ですなあ。

どんな具合に着火装置は出来てるの? ガスレンジ 着火装置 仕組み 検索してみましたよ。 電池を交換してみろってリンナイさんが言ってた。

オイラーの所のレンジは、単1型のものが2本使われていた。FUJIFILM製とは珍しいな。 以前住んでいた人は関係者だったとか、写真をやってて、その縁ででも使っていたのかな。

更にこの電池の素性を調べてみると、生まれはUSA。02-2011って刻印が有った。これって、 生年月日? それとも賞味期限? おいらがこちらに引っ越したのが2010年の初冬。それ から電池交換の記憶は無い。と言う事は、賞味期限って事になるな。よくもまあ、今まで 使えたものだ。液漏れもなく。 余計なプロファイルは、TVの見すぎかな。

プロファイルと言えば、元刑事と言う人が事件現場に出てきて、犯人像を推測してみせるけど、 現役の人の捜査の妨げにならない? それとも、頼りない新人刑事への叱咤激励かしら? みんな、現在進行形の捜査には興味が尽きないですから、一定の需要は有るんでしょうな。

話が逸れた。オイラーの疑問は、3Vの電圧でどうやって火花を飛ばすのって事? トランスで昇圧は直ぐに思い付いた。トランスって交流で意味を成すので、発信器が 必要だな。この場合は直流電流をチョッピングして、インダクタと電流の変化率の積に 比例する逆起電力を利用してるんだなと、想像する。発信器はお得意のNE555、それに1石の スイッチって所だな。トラ技の世界が出てまいりましたな。

仕組みより原理で検索すると、 ガスレンジの点火装置が故障して困っています。 なんてのが出てきた。

そんな難しい事考えなくても、車のエンジンの点火装置を思い浮かべるんだ。そんなの、 16歳で2輪の免許を取った時以来だな。 今は、イグナイター と言うらしい。 点火装置の原理とか 第4話 点火系の話しに出てた。 他にも、デンソーとかが資料を公開してた。電装だけあるな。

たち消え防止装置も説明が有った。ガスコンロに見る物理 によると、熱伝対で温度を検出して、それで電磁バルブを駆動ってなってるけど、そりゃ、 原理だけだろうに。CA熱伝対で、1000度の温度差でも、42mVぐらいしか出なかったはずだから、 そんなんで駆動出来るはずは無い。

レンジの中に、電子基板でも入っていて、直流Ampで電圧増幅してからリミッターを通して、 石で電磁バルブをON/OFFしてるんだろうね。と、これまた、トラ技。

修理屋さんがやってきた。どんな部品を交換するかと眺めていようと思ったら、女房に嗜め られた。修理する所をジロジロ見られるって、緊張してネジを落としたりしますからね。 オイラーも、ふと昔の事を思い出したぞ。

で、結果は、スイッチモジュールが悪かったので、代替品を取り付けましたとの事。部品保有 年限を過ぎていて同品は手に入らないとか。そうでしょうね。製造打ち切りから優に10年は 経過してるから、さもありなん。物理的に違和感なく取り付けられるように設計されて助かったわい。

Nim

Rustがやっと、α2になったかと思うのもつかの間、今度は 注目を集め始めるプログラミング言語「Nim」 ですって。

作者がRustを見切って、新しいのにスイッチしたらしいので、何となくRustに似てるな。 まずは、Nimしてみろとな。

そして、 この頃 流行りの 言語たちでベンチマーク も、参考に。

命令的スタイルと関数的スタイル

各種言語のサンプルと言えば、ハロワとかFizzBuzzが 取り上げられる。 Rustのサンプルを見てたら、2つのスタイルが載ってた。どちらが優れているかなんて事は、 感性の問題なので言わないけれど、こうやって比べてみると面白い。

まずは命令的なやつ

    let upper = 1000u32;

    // Imperative approach
    // Declare accumulator variable
    let mut acc = 0;
    // Iterate: 0, 1, 2, ... to infinity
    for n in iter::count(0u32, 1) {
        // Square the number
        let n_squared = n * n;

        if n_squared >= upper {
            // Break loop if exceeded the upper limit
            break;
        } else if is_odd(n_squared) {
            // Accumulate value, if it's odd
            acc += n_squared;
        }
    }
    println!("imperative style: {}", acc);

お題は、1000までの数について、2乗したものが奇数であるものの和。

    // Functional approach
    fn is_odd(n: u32) -> bool { n % 2 == 1 }

    let sum_of_squared_odd_numbers =
        // All natural numbers
        iter::count(0u32, 1).
        // Squared
        map(|n| n * n).
        // Below upper limit
        take_while(|&n| n < upper).
        // That are odd
        filter(|n| is_odd(*n)).
        // Sum them
        sum();
    println!("functional style: {}", sum_of_squared_odd_numbers);

この例、HOFの所に有ったんだけど、公開関数 もとえ 後悔もとえ 高階関数ってのの略 なのね。こういう省略は一般的なの?

Rust alpha2

http://blog.rust-lang.org/2015/02/20/Rust-1.0-alpha2.html が来てたんで、入れてみた。そして、cargo cleanしてから、bldを実行してみると

[sakae@fedora bld]$ cargo build
    Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading csv v0.12.17
 Downloading rustc-serialize v0.2.15
   Compiling rustc-serialize v0.2.15
   Compiling csv v0.12.17
   Compiling bld v0.0.1 (file:///home/sakae/rust/bld)
src/main.rs:5:5: 5:30 error: unresolved import `std::io::process::Command`. Could not find `process` in `std::io`
src/main.rs:5 use std::io::process::Command;
                  ^~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error

何やら、Commandが居なくなっちゃってる。探してみたら、別の所に移動してた。アルファ版は、 絶賛不安定中。頑張って追従しましょ。

1月半ぐらいでアルファ版が更新された。もう一回ぐらいアルファの更新が有って、それから ベータ版が2回ぐらい。すると、正式版は早くても、7月ぐらいかな。

めげずに、動くようにしてみた。

[sakae@fedora src]$ diff -u old.main.rs main.rs
--- old.main.rs 2015-02-27 07:11:00.738978737 +0900
+++ main.rs     2015-02-27 16:39:46.877955648 +0900
@@ -1,10 +1,17 @@
 #![allow(unstable)]
+#![feature(old_path)]
+#![feature(core)]
+#![feature(old_io)]
+#![feature(env)]
+//#![feature(os)]
+//#![warn(unused_variables)]

 extern crate csv;
-use std::path::Path;
-use std::io::process::Command;
+use std::old_path::Path;
+use std::old_io::process::Command;
 use std::os;
-use std::io;                     // for read_line
+use std::env;
+use std::old_io;                     // for read_line

 static SEED: &'static str = "./2015.csv";

@@ -46,8 +53,8 @@
             "-ss" => op.ss = 1,
             "-lg" => op.lg = 1,
             _     => av = match cv.parse() {  // Must be numbers
-                Some(x) => x,
-                None =>  { op.er = 2; return op; },
+                Ok(x) => x,
+                Err(e) =>  { op.er = 2; return op; },
             }
         }
     }
@@ -186,7 +193,7 @@
                 Err(why) => panic!("couldn't write gnuplot stdin: {}", why.desc),
                 Ok(_) => println!("sent pangram to gnuplot"),
             }
-            let dmy = io::stdin().read_line(); // pause for emacs run
+            let dmy = old_io::stdin().read_line(); // pause for emacs run
         }
         return self;
     }
@@ -196,7 +203,7 @@
     let fg = getopts();
     if fg.er != 0 {
         usage();
-        os::set_exit_status(fg.er as isize);
+        env::set_exit_status(fg.er);
         return;
     }
     let bld = read_csv(SEED);

ワーニングをなるべく抑制するようにスイッチを入れてみたけど、全部は隠しきれず! (正しい態度じゃありませんから、マネしないように) 本質的に変更が有った所は、 parseした時の結果が今までは、Option型で返ってきていたのが、Result型になった所 ぐらいかなあ。

自前のCSVリーダー

今までCSVの読み込みは、他人様の作成したモジュールを使ってた。確かにちゃんとCSV ファイルを読み込もうとすると面倒な事が起こる。それを証拠に、古くはmatzさんが 初めて書いたRuby本にも取り上げられているし、Haskell本にも有った。RFCにも なってるぐらいだからね。

でも、今回のCSVファイルは、そんな複雑怪奇な物ではない。だったら自前でリーダーを 書いてみろ。これぞ車輪の再発明。

えと、ファイルを一行づつ読み込んで、それをカンマを頼りに分割して、そいつを数値に 直せばいいんだな。楽勝。

use std::old_io::BufferedReader;
use std::old_io::File;

fn read_csv(cf : &str) -> Vec<[u32 ;4]> {
    let fp = &Path::new(cf);
    let mut bld = vec![];
    let mut ary = [0xdeadbeefu32 ;4];

    let mut file = BufferedReader::new(File::open(&fp));
    for line in file.lines() {
        let mut c = 0usize;
        for s in line.unwrap().trim().split(','){
            ary[c] = s.parse().unwrap();
            c += 1;
        }
        bld.push(ary);
    }
    return bld;
}

ファイルは使い終わったらcloseするのが流儀だけど、Rustはブロックを抜けた所で 自動的に始末されるんで、それは不要。そして、ファイルの終端に達したかのEOF検査も 旨くイテレーターの中に隠されている。段々Rubyに似てきたな。

カンマで分割した結果は、配列で返ってくるんじゃなくて、イテレーターで返ってくる 仕様は、オイラーにとっちゃ新鮮でした。また、行末文字がくっついてくるんで、それを そのままparseするとエラーになる。そんな事もあろうかと、trimが用意されてるんで、 有り難く使わせてもらいましょう。

anyの配列はu32のデータが格納されるんで、それに合わせてインデックス番号(c)を usizeにしときましょう。オイラー、今の今まで、こういう作法は知らなかったぞ。 自分で作ってみて、苦労が分かるってもんです。

お百姓さんの苦労を知ったら、米粒1粒とも、おろそかにしてはいけません。親の小言は 冷酒のごとく効いてきますなあ。

自前のリーダーで間に合わせたものと、既製品を組み込んだものとで、どのぐらい サイズが違うか調べてみると

[sakae@fedora target]$ size old.bld bld
   text    data     bss     dec     hex filename
 840316   15144    2816  858276   d18a4 old.bld
 758000   14232    2816  775048   bd388 bld

lsで確認すると、約200Kぐらいの差が有りました。

Rustはまだまだ発展中。安定するまで、少し寝かせておこう。