エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

Io FizzBuzz

昨日のFizzBuzz のつづき。

再掲。

久しぶりに Io でコードを書いたら、すっかり作法を忘れてしまっていることに気がつきました。if 文の書き方、期待する動きになるように書けたはいいのだけれど、こんな書き方でよかったのか未だにこころもとない。

Number fizz := method(
  if(self % 3 == 0,
    result := "Fizz"
    result n := self
    result,
    self
  )
)

Number buzz := method(
  if(self % 5 == 0,
    result := "Buzz"
    result n := self
    result,
    self
  )
)

Sequence fizz := method(
  if(self n % 3 == 0,
    result := self .. "Fizz"
    result n := self n
    result,
    self
  )
)

Sequence buzz := method(
  if(self n % 5 == 0,
    result := self .. "Buzz"
    result n := self n
    result,
    self
  )
)

 1 fizz println
 2 fizz println
 3 fizz println
 5 fizz println
 9 fizz println
10 fizz println
12 fizz println
15 fizz println

"---" println

 1 buzz println
 2 buzz println
 3 buzz println
 5 buzz println
 9 buzz println
10 buzz println
12 buzz println
15 buzz println

"---" println

 1 fizz buzz println
 2 fizz buzz println
 3 fizz buzz println
 5 fizz buzz println
 9 fizz buzz println
10 fizz buzz println
12 fizz buzz println
15 fizz buzz println

"---" println

 1 buzz fizz println
 2 buzz fizz println
 3 buzz fizz println
 5 buzz fizz println
 9 buzz fizz println
10 buzz fizz println
12 buzz fizz println
15 buzz fizz println

実行。

$ io fizzbuzz.io 
1
2
Fizz
5
Fizz
10
Fizz
Fizz
---
1
2
3
Buzz
9
Buzz
12
Buzz
---
1
2
Fizz
Buzz
Fizz
Buzz
Fizz
FizzBuzz
---
1
2
Fizz
Buzz
Fizz
Buzz
Fizz
BuzzFizz

Ruby や Io でならば簡単に実現できるこの FizzBuzz。簡単に実現できるその特徴とは。

いつか読むはずっと読まない:へびつかい座

読んで真っ先に思い出した作品がこれでした。

あるいはグレッグ・イーガン

解説にも、 「アイデンティティを揺るがせ、人間の定義を変容させていく行為が日常化した〈八世界〉は、サイバーパンクグレッグ・イーガン作品などの先駆に位置づけられるだろう」 とあり、ギミックは多少時代が感じられるものの、その物語は1970年代に書かれたとは思えない強烈さがあります。

C++で整数値を返したり文字列を返したりする

#include <string>
#include <iostream>

template<int N, bool is_string>
struct this_is_a_int_or_string;

template<int N>
struct this_is_a_int_or_string<N, false> {
    typedef int value_type;
    static const value_type value = N;
};

template<int N>
struct this_is_a_int_or_string<N, true> {
    typedef std::string value_type;
    static const value_type value;
};

template<int N>
const typename this_is_a_int_or_string<N, true>::value_type this_is_a_int_or_string<N, true>::value = "Fizz";

template<int N>
struct Fizz {
    typedef typename this_is_a_int_or_string<N, (N % 3) == 0>::value_type value_type;
    static const value_type value;
};

template<int N>
const typename Fizz<N>::value_type Fizz<N>::value = this_is_a_int_or_string<N, (N % 3) == 0>::value;

template<typename T>
std::string this_is(T);

template<>
std::string this_is(int n) {
    return "int";
}

template<>
std::string this_is(std::string s) {
    return "string";
}

int main(int, char* []) {
    std::cout << Fizz<1>::value << " is " << this_is(Fizz<1>::value) << std::endl;
    std::cout << Fizz<2>::value << " is " << this_is(Fizz<2>::value) << std::endl;
    std::cout << Fizz<3>::value << " is " << this_is(Fizz<3>::value) << std::endl;
    std::cout << Fizz<4>::value << " is " << this_is(Fizz<4>::value) << std::endl;

    return 0;
}

実行。

$ g++ -o this_is_a_int_or_string this_is_a_int_or_string.cpp 
$ ./this_is_a_int_or_string 
1 is int
2 is int
Fizz is string
4 is int

同じ Fizz<N>::value という形でありながら、N の値によって value の値が整数値であったり文字列であったりします。

FizzBuzzクイズ」の実現方法について @Nabetani さんと C++ で書ける書けないという話をした中で、「template でならできるかも」という流れになったので、書いてみました、途中まで。

本当はもう少し先まで書いたのですが…思うところがあって力尽きてしまいました。

「思うところ」は、また後ほど。

いつか読むはずっと読まない:クロニクル

ということなので。

火星年代記 (ハヤカワ文庫SF)

火星年代記 (ハヤカワ文庫SF)

パラダイスバード・クロニクル

パラダイスバード・クロニクル

備忘録:aws-sdk gem を使って AWS S3 にファイルをアップロードする

require 'aws-sdk'

client = Aws::S3::Client.new(
          access_key_id: 'your-aws-access-key-id',
          secret_access_key: 'your-aws-secret-access-key',
          region: 'your-region')

client.put_object(
  bucket: 'target-backet-name',
  key: 'sample.txt',
  body: File.read('path/to/local/sample.txt'))

Aws::S3::Client#put_object - AWS SDK for Ruby V2

Elixir の OptionParser.parse はハイフンをアンダスコアに置き換える

OptionParser.parse(["--show-all"], [switches: [show_all: :boolean]])
# => {[show_all: true], [], []}
OptionParser.parse(["--show_all"], [switches: [show_all: :boolean]])
# => {[], [], [{"--show_all", nil}]}

Elixir converts switches to underscored atoms, so --source-path becomes :source_path.

OptionParser.parse - Elixir

「どう書く」をElixirで書いたときのテストを簡単にする

Elixir でコールバックってどうやって実装しているのだろうと調べてみたら、マクロで実現されていました。なるほど。 その昔 C 言語でマクロを使ってコードを生成していたのを思い出した。

そんなわけで。マクロを使って「どう書く」のテストを実行するモジュールを書いてみた。

Elixir のドキュメントにテストの説明があったので、だいたいそのまま。

テストランナ

結果判定をする通常の関数 judgeuse されたときに実行される __using__ マクロ、個々のテストを定義する test マクロ、コンパイル時に実行される __before_compile__ マクロからなっています。

__before_compile__ が実行されるようにするには、@before_compile で指定する必要があるようです。

defmodule Doukaku.TestRunner do
  def judge(_, expected, expected) do
    IO.puts "\x1b[32mpassed\x1b[0m"
  end

  def judge(input, expected, actual) do
    IO.puts "\x1b[31mfailed  input: #{input}, expected: #{expected}, actual: #{actual}\x1b[0m"
  end

  defmacro __using__(_) do
    quote do
      import Doukaku.TestRunner
      @tests []
      @before_compile Doukaku.TestRunner
    end
  end

  defmacro test(input, expected) do
    quote do
      @tests [{unquote(input), unquote(expected)}|@tests]
    end
  end

  defmacro __before_compile__(_) do
    quote do
      def run do
        @tests
        |> Enum.reverse()
        |> Enum.each(fn {input, expected} -> judge(input, expected, solve(input)) end)
      end
    end
  end
end

どう書いたコードの例

英字の小文字だったばあいに大文字に変換するとかそういうの。

テストを定義する部分は CapitarlTest などに分離するのがきれいなのかもしれません。

defmodule Capitarl do
  use Doukaku.TestRunner

  def to_capital(c) do
    c - 32
  end

  def solve(input) do
    input
    |> String.to_charlist
    |> Enum.map(&to_capital/1)
    |> List.to_string
  end

  test("a", "A")
  test("ab", "AB")
  test("Ab", "AB")
end

Capitarl.run

実行

本当はパッケージにまとめておくのが正解の気がしますが、今回はファイル 2 つだけですまそうと。

テストランナをコンパイルします。

$ elixirc doukaku/test_runner.ex

どう書いたコードを実行します。

$ elixir capital.exs 
passed
passed
failed  input: Ab, expected: AB, actual: !B

いつか読むはずっと読まない:どこかで聞いた気がする

懐かしいとはちょっとちがう、どこかで聞いた気がする、という感じが集まった一冊。

一番にそれを感じたのが最後の防火水槽のくだり。

里山奇談

里山奇談

なお、「今日の早川さん」の第 4 集が控えているらしい。

今日の早川さん (早川書房)

今日の早川さん (早川書房)