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

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

ビットをもっと自由自在に扱える言語

Elixir を学んでいます。

ビットをもっと自由自在に扱えるようにしてみた

7 年ほど前にビット操作を支援するコードを C++ で書いたことがあります。

ビットをもっと自由自在に扱える言語

同じようなこと、それ以上のことが Elixir は言語として用意されています。20 年前の自分に教えてやりたかった。

# color.exs

defmodule Color do
  def from16to24(bitmap) do
    (for << r::5, g::6, b::5 <- bitmap >>, do: <<r::5, 0::3, g::6, 0::2, b::5, 0::3>>) |> Enum.join
  end

  def from24to16(bitmap) do
    (for << r::5, _::3, g::6, _::2, b::5, _::3 <- bitmap >>, do: <<r::5, g::6, b::5>>) |> Enum.join
  end
end


iex で実行。

$ iex
iex> c "color.exs"
iex> Color.from16to24 <<0xffff::16>> 
<<248, 252, 248>>
iex> Color.from24to16 <<255, 255, 255>>
<<255, 255>>

元祖ビットをもっと自由自在に扱える言語

Erlang でも。

% color.erl

-module(color).
-export([from16to24/1, from24to16/1]).

from16to24(Bitmap) ->
  << <<R:5, 0:3, G:6, 0:2, B:5, 0:3>> || <<R:5, G:6, B:5>> <= Bitmap >>.

from24to16(Bitmap) ->
  << <<R:5, G:6, B:5>> || <<R:5, _:3, G:6, _:2, B:5, _:3>> <= Bitmap >>.


erl で実行。

$ erl
> c(color).
> color:from16to24(<<255, 255, 255, 255>>).
<<"øüøøüø">>
> color:from24to16(<<255, 255, 255>>).     
<<"ÿÿ">>

文字として表示できる値の場合に文字として表示してしまうのやめて欲しいぞ。

> <<R:5, G:6, B:5>> = color:from24to16(<<255, 255, 255>>), io:format("~p~n", [[R, G, B]]).
[31,63,31]
ok

いつか読むはずっと読まない:リンの眼、クウィルの手

Redis Pub/Sub in Elixir 覚書

Exredis を使っています。

defmodule Subscribe do
  def sub(channel) do
    {:ok ,client_sub} = Exredis.Sub.start_link
    pid = Kernel.self

    Exredis.Sub.subscribe(client_sub, channel, fn msg ->
      send(pid, msg)
    end)

    receive do
      {:subscribed, ^channel, _pid} ->
        IO.puts "OK"
    end

    loop(channel)
  end

  def loop(channel) do
    receive do
      {:message, ^channel, message, _pid} ->
        IO.puts message
        loop(channel)
    end
  end
end

どこかで起動しておく。Redis も起動しておく。

> Subscribe.sub("test")
OK


Pub 。

> import Exredis
> Exredis.Api.publish(client, "test", "Hello")


こんな風に表示されます。

> Subscribe.sub("test")
OK
Hello


Ruby でも。

require 'redis'

r = Redis.new
r.publish('test', 'Hello')
> Subscribe.sub("test")
OK
Hello
Hello

RPN in Elixir

# Rpn.eval "3 1 - 2.1 +"
# => 4.1

defmodule Rpn do
  def eval(expression) do
    eval(tokenize(expression), [])
  end

  defp eval([], [result]), do: result
  defp eval(["+"|tokens], [rhs, lhs|stack]), do: eval(tokens, [lhs + rhs | stack])
  defp eval(["-"|tokens], [rhs, lhs|stack]), do: eval(tokens, [lhs - rhs | stack])
  defp eval(["*"|tokens], [rhs, lhs|stack]), do: eval(tokens, [lhs * rhs | stack])
  defp eval(["/"|tokens], [rhs, lhs|stack]), do: eval(tokens, [lhs / rhs | stack])
  defp eval([value|tokens], stack), do: eval(tokens, [value | stack])

  defp tokenize(expression) do
    tokens = Regex.scan( ~r/(?<op>[\+\-\*\/])|(?<float>\d+\.\d+)|(?<int>\d+)/, expression, capture: ["op", "int", "float"])
    Enum.map(
      tokens,
      fn
        ([op, "", ""]) -> op
        (["", int, ""]) -> String.to_integer(int)
        (["", "", float]) -> String.to_float(float)
      end
    )
  end
end


Regex.scan/3 がいささかトリッキー。使い方が合っているのか判断がつかない。

span

練習。

% span.pro

:- module(span, [span/2]).

span(From, From, [From]) :- !.
span(From, To, [From|Span]) :-
  From < To,
  From1 is From + 1,
  span(From1, To, Span),
  !.
% span-test.pro

:- include(span).

main :-
  span(1, 10, S),
  format("~p~n", [S]),
  halt.


実行。

$ gprolog --consult-file span-test.pro --entry-goal main
[1,2,3,4,5,6,7,8,9,10]


通常使うには between で充分なのだけれど。

$ gprolog
| ?- findall(N, between(1, 10, N), NS).
NS = [1,2,3,4,5,6,7,8,9,10]
yes

オブラブカレンダーができました

やがて1月も終わろうという時期ですが。
2017 年版オブラブカレンダーができました。


去る 1 月 11 日 には事業部のご挨拶とともにできあがったカレンダーをお渡しする会を開きました。

まだ若干数ありますので、ご興味のある方はオフィスにお立ち寄りいただけたらと思います。

ところで。私とオブラブカレンダーについて

ご挨拶の会でも話をしたのですが、今の仕事をするきっかけは 10 年ほど前に参加したオブラブイベントがきっかけでした。
巡り巡って今の会社に移り今の仕事が始まったわけですが、たびたびイベントに参加していたとはいえ外から見える景色と中から見える景色はかなり違います。
そんな中で、刷り上がって納品されたオブラブカレンダーの束を見たとき、ようやく「中の人」の実感が湧いてきたのを覚えています。外から見えていたものをようやく内側から見えた、そんな感じです。

これは、手元に残っているおそらく最古のオブラブカレンダー。見ると 2007 年版。図らずしもちょうど 10 年前のオブラブカレンダー。

Prolog だって Key-Value を扱いたい

不思議な記述を見つけました。

An object in JSON is presented as a bunch of keys and values within curly braces, in Prolog I have used a function and a KV list like so:

obj([key1-value1, key2-value2, ...]).

Present your terms like that and everything should be fine. See the source file json_encode.pl for a full explanation and some examples that should hopefully explain it all.

https://github.com/emacstheviking/gnuprolog-json


Prolog に “key-value” といった記法があったけ? と数日考え込んだのですが、Prolog では明示的に評価するまで記述した内容がそのまま値として扱われるということを利用しているということに思い至りました。

$ gprolog
| ?- A = 2 - 1.
A = 2-1

変数 A の値は 1 ではなく 2-1 であることがわかります。
2-11 とはマッチしません。

| ?- 1 = 2 - 1.
no

2-1 を明示的に評価することで値として 1 がえられます。

| ?- A is 2 - 1.
A = 1
yes
| ?- A is 2 - 1, 1 = A.
A = 1
yes

と、いうことは。評価前であれば演算子 - も含めた形で変数にマッチさせることができます。

| ?- A - B = 2 - 1.
A = 2
B = 1
yes

- の演算は評価されないので、数値でなくても構いません。

| ?- A - B = abc - def. 
A = abc
B = def
yes

評価すると当然のようにエラーになります。

| ?- A is abc - def.   
uncaught exception: error(type_error(evaluable,abc/0),(is)/2)


これが “key-value” の正体だったようです。


これらを踏まえて。
key_value.pro を用意。

find(_, [], not_found) :- !.
find(K, [K-V|_], V) :- !.
find(K, [_|KVs], V) :- find(K, KVs, V).

GNU-Prolog で実行。

$ gprolog
| ?- ['key_value.pro'].
yes
| ?- find(a, [a-1, b-2, c-3], V).
V = 1
yes
| ?- find(b, [a-1, b-2, c-3], V).
V = 2
yes
| ?- find(c, [a-1, b-2, c-3], V).
V = 3
yes
| ?- find(d, [a-1, b-2, c-3], V).
V = not_found
yes


ペアが作れればよいので [ [a, 1], [b, 2], [c, 3] ] でもよいのですが、見やすさ書きやすさ誤った形式の排除という点で key-value という記述のメリットはありそうです。

ちなみに。
評価されなければよいので演算子- でなくても構いません。

| ?- A + B = abc + def.
A = abc
B = def
yes
| ?- A / B = abc / def.
A = abc
B = def
yes
| ?- A : B = abc : def.
A = abc
B = def
yes

いつか読むはずっと読まない:青春ものだった

私はサンリオSF文庫は読んだことはないのですが、こうして復刊されたものを読むと良書ぞろいだったのだろうなぁと思わずにはいられません。

ハローサマー、グッドバイ (河出文庫)

ハローサマー、グッドバイ (河出文庫)