いものやま。

雑多な知識の寄せ集め

『処理から設定へ』というLTをしてみた。

8/24(水)におなじみラスクさんのLT会で『処理から設定へ』というLTをしてみた。

この「処理を設定に抜き出すことで見通しをよくする」という手法、たぶんみんな無意識にやってるんだけど、ちゃんと名前がつけられていない印象。 本とかでも見たことない気がするんだよなぁ。

ちなみに自分がこの手法をちゃんと知ったのは研修でオセロのプログラムを書いてたとき。 石が置けるかのチェックで、普通は上、右上、右、・・・と走査するコードをそれぞれ書くことになるけど、これをdx, dyという設定として持つことで、コードは1つで済むようになるというもの。 そのときの講師に言われてなるほどとすごく感心したのを覚えている。 この手法は変種オセロを書いたときにも使ってる。

あと、FizzBuzzの書き換えの方法を使うと、未使用変数の話をしたときのコードは次のように書けたりもする:

from typing import Callable, Any

# ルール記述のための部品

AcceptFunc = Callable[[str], bool]
TransFunc = Callable[[str], str]

def is_between(first: str, last: str) -> AcceptFunc:
    return lambda c: first <= c <= last

def always(c) -> bool:
    return True

def add_offset(offset: int) -> TransFunc:
    return lambda c: chr(ord(c) + offset)

def identity(c) -> str:
    return c

def convert_with_rules(c: str, rules: list[dict[str: Any]]) -> str:
    for rule in rules:
        if rule["accept?"](c):
            return rule["convert"](c)

# ルール記述

TRANS_RULES = [
    {"accept?": is_between("a", "m"), "convert": add_offset(13)},
    {"accept?": is_between("A", "M"), "convert": add_offset(13)},
    {"accept?": is_between("n", "z"), "convert": add_offset(-13)},
    {"accept?": is_between("N", "Z"), "convert": add_offset(-13)},
    {"accept?": always, "convert": identity},
]

# 変換メソッド

def transform_letter(c: str) -> str:
    return convert_with_rules(c, TRANS_RULES)

def transform(input_: str) -> str:
    return "".join(map(transform_letter, input_))

部品の部分がラムダ式を返す関数だったりして関数型の考えに慣れてないとちょっと分かりにくいけど、面白いのはルール記述の部分で、変換のルールがそのまま記述された感じになっているのが分かるかと思う。 実際には部品の部分はライブラリとして提供すればいいので隠蔽できるし。

今日はここまで!