見出し画像

Retro-gaming and so on

RE: プログラミング学習日記 2024/02/13〜

龍虎氏の記事(2024/02/13と2024/02/14)に対してのコメント。

ふふふふ(笑)。面白い事をやってる(笑)。
しかし、スタックオーバーフローの連中も面食らっただろうなぁ(しかも、相手は「Lisper」だから無下にも出来ないし、ある意味楽しんでたんじゃないか・笑)。
でも、いっつも言ってる通り、「ある重要機能を使いこなす」には、ギリギリを攻めるのが一番なんだ。
それが「いつそれを使えて、いつそれが使えないんだ」と言う「見切り」を育てる。
だから練習段階ではアレコレ考えて「無理をしてみる」べきだ。

んで、確かに回答者の一人が言ってる通り、

「元となる数値が次第に減っていき, 除数より小さくなれば終了」
というパターンは (for 〜 in sequence の処理には) 向かない

っつーのはその通りなんだ。単項の数値がどうの、と言うとリスト内包表記での処理が難しくなる。
実は仮に「連続してある数値を割ってリストを生成する」rangeがあれば、この問題は一挙解決だ。そうすれば「単項からリストが生成出来る」・・・・・・どっかで聞いた事がない(笑)?
そう、実はこれ、最近、僕のブログの方で扱ってる余再帰向けの問題、なの。
苦しくも、回答者が、

ジェネレーターが必要になりそう

って言ってるのはその通り、なんだ。
問題はその「ジェネレータ」をこの問題に特化したカタチで書くのか、あるいは汎用性があるように作るべきか、ってので方針が違う。そして余再帰関数unfoldは後者の方針なんだ。

実際、この問題、SchemeだとSRFI-1のunfoldで一行で書けてしまう。

> (reverse (unfold zero? (lambda (x) (modulo x 2)) (lambda (x) (quotient x 2)) 499))
'(1 1 1 1 1 0 0 1 1)

このリストが正しいか否かは次のようにして確認出来る。

> (number->string 499 2)
"111110011"

正しいよね。

つまり、Pythonで数学をやって、このテのパターンが今後も出てくるとしたら、余再帰関数を自作して、ライブラリ化しておいてもいいと思う。Pythonに足りないのは余再帰だ、って今ここでハッキリしたわけだから。
もう一度、余再帰関数unfoldrの定義を置いておく・・・Pythonだとunreduceの方がいいのかもしれんが(笑)。

### 余再帰
class unfoldr:
 def __init__(self, f, seed):
  self.f = f
  self.seed = seed
 def __iter__(self):
  return self
 def __next__(self):
  match self.f(self.seed):
   case a, b:
    self.seed = b
    return a
   case None:
    raise StopIteration
 def __reversed__(self): # reversed を簡易に行う為の特殊メソッド
  return reversed(list(self))

そしてPythonだと

  • リストに何かをマッピングしてリストを得る: リスト -> リストならリスト内包表記
  • リストを何らかの単項データへ畳み込む: リスト -> 何かのデータならfunctools.reduce
  • 単項から何らかの規則に従ってリストを生成する: 何らかのデータ -> リストならunfoldr
と言うのが見えるんじゃないか。
3種の神器(マジでだ・笑)を揃えれば、Pythonでも畏れるモノがない、ってこったな(笑)。

なお、上のunfoldrの定義(Haskellスタイル)だと、与題は、

>>> list(reversed(unfoldr(lambda x: None if x == 0 else (x % 2, x // 2), 499)))
[1, 1, 1, 1, 1, 0, 0, 1, 1]

と簡単に一行で書けます。
  • Xでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

最近の「RE: プログラミング学習日記」カテゴリーもっと見る

最近の記事
バックナンバー
人気記事