ゆくゆくは有へと

おかゆ/彼ノ∅有生 の雑記

ko jbosarxe .iu ciska -1 mo'o-

www.adventar.org

16日目です。もう折り返し地点ですね。

「か、勘違いしないでよねッ!こ、コこッこれは別に、私がそう思ってるってだけなんだから……」

はい(はいじゃないが)。

{ko jbosarxe .iu ciska} 「ロジバン調和的♡に書こう」(直訳)という題です*1*2

この記事のコンセプトは「ロジバンの基礎的な部分を少し意識して、ロジバンに馴染んだ表現を心がけてみよう」です。

ma jbosarxe

「私たちが表現したロジバンが、ロジバンらしさだよ!」*3というのはもっともですが、ロジバンはそれでもやはり「哲学的言語」あるいは「工学言語」です。そこにはロジバンの根本の構築を手掛けた製作者たちの何らかの意図があると思うわけで、いくら「ロジバンが無色の粘土で、表現者次第でいろんな色を付けられる」としても、その意図と完全に反するような開発や表現は、―おそらくロジバンはそれを許容し、そしてかつ実現さえしてくれるでしょうが―あんまりキレイな色に仕上がるとは思えないというのがおかゆの気持ちです。

あるいは:確かに無色の粘土だし、それに表現者がいろんな色をつけて遊ぶことはできるけど、やっぱり根本の思想に基いたスタイルを使えば、よりシンプルで素直な表現ができるだろう、というのはあると思うわけです。プログラミング言語でも「そのスタイルで実装できなくはないけど、その言語の哲学・仕様上、このスタイルで実装したほうが分かりやすいし素直」みたいなことあると思いますが、それと似たような感じです(プログラミング言語もロジバンも人工言語ですからね)。

というわけで、そういう「根本の思想に基いたスタイルを使った表現」というのをこの一連の記事では {jbosarxe} と称したいと思います。

一連の記事でやること

ですから、やるべきことは喩えるなら「ロジバンが無色になりきれてないところってどこだろう?」ということを追求することです。 とはいえ、この追求はある意味で jboske(ロジバン学)における究極的な問いかけへの挑戦にも思えます。 恐らくヲかゆは今回の2016年アドベントカレンダーでこのことに完全に答えることはできないでしょう。 それでも、ここでいくらか足掻いておけば、まあ誰かが続きを考える材料くらいにはなるでしょう a'o。

対象のタイプについて

おかゆが最初に目をつけるのは「ロジバンで現れる対象のタイプ」です*4

ロジバン学習の途中で、{tu'a} について学ぶときに "sumti-raising"(sumti昇格)という用語に出会うかと思います。これは「モノはコトではありえない」という認識からくるものでしょう。一般的に「出来事」が入るべき述語の引数位置に「物」を入れることはできないので、{tu'a}を冠する必要がある、というわけです*5

というわけで、ロジバンの not unofficial な機能語としてそういう「対象のタイプ」を意識した語があります。ですから、ロジバンに現れる対象のタイプをきちんと把握することは、jbosarxe に一歩近づく道だと思うわけです。

では、ロジバンの世界には一体どんなタイプの対象があるのでしょう?有名な入門講座 lojban wave lesson に "Types" という章があり、そこではまさにロジバンに現れる対象のタイプについて説明がなされています。あいにく、この章はまだ日本語訳されていませんから、まずはこの章の内容をかいつまんでいきます。

lojban wave lessons - Types

知りたいのは、ある程度共通認識となっている(であろう)対象のタイプに関してです。LWL(Lojban wave lessons)では、次のタイプを挙げています:

  • Material object
  • Event
  • Selbri
  • Amount
  • Concept
  • Bridi
  • Text
  • Set
  • True value

雑に日本語で:

  • 物体
  • 出来事
  • selbri・属性・関係
  • 概念
  • bridi・命題
  • 文・テキスト
  • 集合
  • 真理値

の9種です*6。それぞれが具体的にどういうものなのかというのは、補足として最後に載せておきます。確かにそれぞれの対象が何であるかというのは理解のために必要ですが、「何であるか」という問いに一定の答えを与えようとするにはどうしても一つの哲学的立場を導入しないといけないと思うからです。

おかゆ的には、これに「数値・数」を入れるべきかと思います。{li pa} とか、そういう表現が表示する対象です。

というわけで、ロジバンに出てくる対象は、合計10種類のタイプのどれかだということになります。物体タイプには膨大なサブタイプがあるだろうというのは分かるとしても、それだけ?という感じはします。

「物体タイプがカテゴリとして膨大すぎる」という意見があるかもしれませんが、まあこれは程度問題でしょう。いずれにせよ、物理的実体という大きな枠組みがあることは確かです。むしろ、そんなことよりももっと重大なことに気づくべきです。

「時間」と「空間」はどこ行った?

と、その前に:「対象が存在する」ということについて

ロジバンの「時間」と「空間」について考える前に、そもそも「ロジバンの世界に現れる対象」ってなんなのかという話をしておきます。

「対象が存在する」、もう少しおかゆ的にきちんと言えば「ロジバンにおいて対象化される」とは、項の値になれるということです*7。有り体に言ってしまえば、{da} や {bu'a} によってアクセスできないようなものは、ロジバンでは存在言明ができません。そのようなものは、「ロジバンの世界において対象化されない」、あるいは「ロジバンの世界においては存在しないもの」として扱うことになるでしょう。だって存在論的言及に引っかからないんだもん( ᕦ 。 ᕤ)

さて、ロジバンは内容語として(少なくとも gismuだけを考えても)1000以上の述語を備えています。これはロジバンにおいてどんなものが対象化されるのかということを規定し(てしまい)ます。用意された述語セットによってどんなものが {da} されるのかがある程度決まってしまうという話です。この基本セットは、ロジバンの根本的なところの存在論(これはまさに「無色になりきれていない」ところ)を規定します*8*9

おかゆは、余程のことがない限りgismuセットに現れないものは今後も現れないと考えます。これらの述語セットは、互いに結びついて、ネットワークを形成します。このネットワークのおかげで、ある述語の項の値になれる対象はそのネットワークに参与することで、ロジバン世界に上手く組み込まれることになります。もちろん、述語の基本セットの下では現れないような対象も、新たに内容語を導入することで(無理やり)対象化することができます。しかし、そのようにして対象化した対象は、他のどの述語の項の値にもなれないわけで、既存の述語ネットワークからは孤立した存在です。そのような対象がロジバン世界において有意義であるとは思えません。「余程のことがない限り」と言いましたが、このことを踏まえて、その対象を項の値とするような述語の拡張セットをつくり、その小さなネットワークを既存のネットワークとうまく接続してやれば、その対象は細々とではありますがネットワークの中に上手く組み込まれることになり、いくらか使用に堪えるようになるはずです。

ロジバンの対象タイプの少なさを意識しよう

直前の話は、結局のところ、なぜ「時間」と「空間」がロジバンの対象のタイプにないのかということの一定の答えになります。単純に「述語の項の値にならないから」です。「どこ行った?」と言いましたが、そもそもこの2つは対象として「ロジバンには存在しない」というのがおかゆの答えです*10

しかしこのことは、時間的・空間的なことに関する言明がロジバンでは不可能だということではありません。ロジバンでは、そのような言明を、時間・空間を対象化せずに、手元にある少数のタイプの対象を用いて間接的に行ないます

detri : x1 is the date [day,{week},{month},year] of event/state x2, ...

djedi : x1 is x2 full days in duration (default is 1 day) ...

ロジバンでは、日付―出来事の時間的な位置―を、時間という対象に言及せず、数(tcika1)と出来事(tcika2)の関係によって間接的に表現します。同様に、出来事の時間的長さも、そのような対象を用意せずに、あくまで出来事の一性質(正確には出来事と数の関係)として表現するのみです。あえて「時間」の在り方について答えるとすれば、それは「述語の中」ということになります、対象化されないがしかし言及すべきことについて述語が上手くラッパーとして働き、既存の少数の対象タイプによってそのことについて語れるようになっている(逆に言えばそのようにしか語れないようになっている)わけです。

このことから引き出される最も重要な教訓は、自然言語の名詞句表現に対応する項表現が必ずしもあるわけではないということでしょう。まあこのことはどんな2つの自然言語にでも言えそうですが、ロジバンではより顕著だと思います。他言語において名詞で(対象的に)表されるものが、ロジバンでは述語に組み込まれた形で(つまり対象としては存在せずに)存在しているということが往々にしてありえるわけです。

ロジバンには概ね10種の対象のタイプがあり、述語はそのタイプだけを項の値として取るようにインターフェースを整えています(実際は先述の通り、述語がそのような仕様だから結果的に対象のタイプの在り方がこのようになっているわけですが)。このことを意識しておけば、他言語のどの部分を項として、どの部分を述語として分析してロジバンに翻訳すべきかということがかなりスムーズに行えるのではないかと思います。そして、当の目的である jbosarxe な表現というのは、明らかにこのインターフェースに従った書き方によってなされるはずです。

あとがき

書きたいことは割と書いてしまいました。2 mo'o はあるかもしれませんが、それはアドベントカレンダーの外かもしれません。お疲れさまでした。

補足:9タイプそれぞれの概要

物体(Material objects)は、時空間上に居場所をもち、時間経過に対して不変(非時間的)であるように捉えられるような対象のタイプのことです。

出来事(Event)は物体と同じく時空間上に位置するものの、物体と異なり時間経過に従って展開するようなものとして捉えられるような対象のタイプのことです(直観的に「出来事」で捉えていいと思います)。端的にいって、nu1 です。*11

属性・関係(Selbri)は、端的にいって ka1 のことです。出来事とちがって非時間的な抽象的対象です。「緑であること」「愛すること」等々。属性か関係かというのは、単純にロジバンでは節内の{ce'u}の数によります:1つなら属性で、それ以上なら関係です。そう考えるとたしかに Selbri と呼んじゃうほうがロジバンでは自然な気がします。

量(Amount)は、端的にいって ni1 のことで、或る性質がどれだけ適合しているかを表すような対象のタイプです。量は、定量が実際に可能かどうかはさておき、何らかの数で表現されるようなものです*12

概念(Concept)は、端的にいって si'o1 のことです。ka や ni と顕著に異なるのは、節の無記述な位置の引数が zo'e でなく全て ce'u と解釈されることです。

BPFK Section: Abstractors - La Lojban

ヒントとして、恐らくロジバンの概念は概ね「[内容語の大意]という概念」というところのものです*13。ひとつの考え方によれば、対応する概念を理解することで話者はその内容語を適切に使えるようになります。たとえば、私たちが或る事態を {klama} という内容語を述語に用いた文で表せると思えるのは、{klama}の概念を理解していて、事態をそのように分析・分類できるからです。*14

命題(Bridi)は、端的にいって du'u1 です。素朴には「叙述文の表すこと」です。たとえばロジバンの文法講座で、ある形式の文と別の形式の文の意味が同じだというのは、概ね、その2つの文がそれぞれ表す命題が同じものだということです。

テキスト(Text)は、テキストです。表現と言ってもいいかもしれませんが、まあ、テキストです。

集合(Set)は、あの数学の集合のことです。

真理値(Truth value)は、端的にいって jei1 です。True とか False とか Mostly true とか、そんなアレです。数字で表現できますが、数字そのものではありません*15

補足:「空間」はないのか?

本文では「時間」が確かにロジバンでは述語に内部化されていることは見ましたが、「空間」については見ませんでした。それは単に「微妙だな~」と思ったからです。

ただ、この話、少し長くなりそうなので、2 mo'o にまわします。

先取りしておくと、経験的にロジバンで空間・場所・位置を指示するようなことがあったような気がするけど、あれはどうなんだろう?…というあたりです。

co'oru'e

*1:{cusku}のがより正しいとは思うが、まあいいでしょう

*2:これを書こうかなと思ったのは2週間前で、そのときちょっとテンションが高かったので、今は後悔しています .u'uru'e

*3:某さおりん

*4:以下で論じる「タイプ」というのは論理学の用語でいえば恐らく「ソート」に相当するものです

*5:実際の運用で「出来事」が入るべきところに、一般に「物」を表す表現が入っていた場合、聴き手にできることは2つあります:1つはsumti昇格で、そのような「物」が関わっている「出来事」と解釈すること。もう1つは、本来「物」として捉えられる対象それ自体を「出来事」として捉えようとすること。

*6:実は Function もありますが、これは Selbri, Amount, Concept の総称としての分類なので抜きました

*7:Technicalな話をすると、ここで言った「項」というのは一階述語論理的な項だけでなく、少なくともロジバンデフォルトにおいては二階述語論理的な項(つまり述語)も意味します。試験的cmavoも含めれば、{bu'ai}がありますからより高階の述語論理における「項」も意味しえます。

*8:ここは少し暗黙に前提を入れていて、「ロジバンの基本単語セットをすべて受け入れるのであれば」の話です。

*9:さらに言えば、これは少し語弊があります。「根本的なところの存在論」と言ったのは、個々にどういったものが存在するかということよりは、どんなものが差異化・相対化されるような存在論的構造かというようなことです。後述のネットワークという語を使えば、各話者はその述語ネットワークの構造だけを共有していれば十分で、そのノード(項の値)が具体的にどんなものであるかということについては各話者の存在論によるはずです(なんか難しくなってきたので逃げます)。

*10:ただし「空間」については議論の余地があります。詳しくは補足で。

*11:架空の出来事はどうなんでしょうね。おそらく、「時空間上に位置する」というのは客観的事実としてではなく、あくまでその対象に対しての話者の認識・捉え方がそうであるということでしょうから、架空の出来事であっても、それが出来事タイプとして捉えられているなら出来事でしょう。

*12:とはいえ、やっぱり原理的に定量不可能なものの量(ボブとの友だちである量;ボブとの友情量?とか)にはあんまり使用しないほうがいいだろうという声もあります。……でも、「定量可能性」って何???

*13:もちろん、si'o は節をとるので、正確に言えば、「[内容語に相当するような表現の大意]という概念」とでも言うべきです

*14:このあたりの話は、ロジバンの内容語がすべて述語的であることとかなり深く関連すると思っています。たとえば、ロジバンにおいて、私たちは日本語の名詞「犬」に対応するいう概念を持ち合わせてはいません。あくまで私たちは {gerku} という或る事態的・関係的な概念を持っているだけであり、…つまり、個体的な概念というのはロジバン話者としては持ち合わせていないはずです(ただ、この分析は少し古いかもしれず、認知言語学のフレーム理論とかベース・プロファイル関係を用いれば、日本語においても実際はロジバンのような関係的な概念をもっているだけ…というような話になるかもしれません。ただ、あまり詳しくはないので、この程度に留めておきます)。

*15:と言いながら、LWLでの例文は{li pi bi jei la tinjin cu mikce}となっており、jei1 は数が入っていました。もし jei1 に数が入るのであれば、ロジバンの対象タイプに真理値なんてないでしょ…と思うのですが、よく分かりませんね。おかゆとしては、「数字で表現できる」という以上、真理値(jei1)とその数値による表現を関係づける述語を用いて記述すべきだと思いますが。或いはせめて、{la'e li pi bi jei la tinjin cu mikce} にしてほしいですよね。とはいえ、{la'e}による間接的な参照でしか真理値という対象がありえないのなら、本文中でも述べた通り、わざわざ真理値なる存在にロジバンでアクセスするのは na jbosarxe かと思います。

ConEmu の設定メモ

サンシャイィ~~~~~~~ン

Co~

nッ!バシュッ!

E~muゥ……

イェェエエエエエエエエエエエエエエエエエエエエエエエエエ!

サンシャイン池崎だいすき、おかゆです。

conemu.github.io

ConEmu は、いい感じのターミナルエミュレータ?です*1。おかゆは情弱で Emacs とか Vim とかはちょっと使えない人*2なので、ConEmu を入れています。

だいぶ前に ConEmu は入れて愛用していたんですが、別PCに入れる際に設定のこと全く忘れていたのでこの機会にと思いメモ。
というか、お役立ちページをまとめておく。

ちなみにインストール版を使いました。

Windows:コマンドプロンプト代替をConsole2からConEmuに変更

  • Main の monospace のチェック外し
  • Main > Size & Pos, AlignmentのCenter console…にチェックを入れて、右側のPad Sizeに 10px 設定。
  • Main > Appearance, Title bar (caption)…のHide caption always(タイトルバーを無くす;すっきりして可愛くなる)。
  • IntegrationのRegisterボタンを押す(エクスプローラで右クリックから ConEmu 起動できる)
  • Features > Colors から Schemes を "monokai" に(お好きなのをどうぞ)

上のサイトを参考に基本の5項目を設定。さて次~

qiita.com

フォントを変えたいならこれに従う。色々試した感じ、結局 Ricty Deminished かなって感じ。

  • 画面を縦横に分割したい場合は、右上の + ボタンを右クリック -> "New console split" をお好きに。

今回使わなかったけど今後読むかもしれない記事たち

qiita.com

qiita.com

qiita.com

*1:ふくし…?の大学に通ってるんですけど!

*2:お米

おかゆ大反省会会場

www.adventar.org

はじめに

iuk.hateblo.jp

数か月くらい放置しきった「はじロジ」の続きを書いていきたい。「つよくてコンティニュー」

数か月くらい放置しきった「はじロジ」の続きを書いていきたい。「つよくてコンティニュー」

2016-01-04

はい(はいじゃないが)。

1年越しで未完(🍊)という mabla な事態になりそうですが、「まあそんなみんな期待してないっしょ(へらへら)」って内心思ってました。

ほんとうに申し訳ありませんでした fau'usai

というわけで、2016年におかゆのアホがやり残したことをここに書き連ね、もしおかゆがやり損なっても他の誰かが仕上げてくれることを期待して2017年へのおかゆに牽制しようと思います。

はじめてのロジバン第二版

はよ書けよ。

はじめてのロジバン 第2版 - はじめてのロジバン第2版

lojban wavelesson 日本語訳のレイアウト

参考:Google グループ

これは2016年になって尚やってないことですね。

2014年の終わりに、私のブログ「味噌煮込みロジバン」で日本語訳していた lojban wavelesson を le uitki に移行しました。

lojban wavelessons 日本語版 - La Lojban

とはいえまだレイアウトがぐちゃぐちゃのままで「いつかやんないとな~」って思いながら2年経ちましたね……。

確かこの翻訳の底本は2013年秋頃の英語版で、その頃からちょっと(割と?)内容が変更されてたりするので、その辺りも吸収しないといけない。

「まあ誰かやってくれるやろ」では誰もやらないということのいい事例ですね(戒め)

救世主

PJCG gimste Lv2

PJCG gimste lv2 プロジェクト - pre

iuk.hateblo.jp

lela.iúk.tánxe - PJCG gimste

PJCG(日本ロジバン若手の会)で初学者用の gismu リストを作ろうという企画の第二弾。

Evgeni シソーラスを少し改変したものを使って再編しようという流れで、そのシソーラスの改変の途中で止まってしまっている…。

そうこうしてる内に、新しいシソーラス(?)が誕生したようだ(おそらく glekiさんが手がけたもの):

semantic classes of verbs - La Lojban

新しい(とはいえ2013年ですが、Evgeniのよりは新しい)ということもあり、こっちを参考にしたほうがいいかもしれないと最近は思っている。 ひとまずは日本語訳からですね。

ロジバンアスペクト

iuk.hateblo.jp

前議論しかしてない…。

おかゆとロジバンのアスペクトの戦いはこれに始まるわけでなく、「味噌煮込みロジバン」でもかなりの記事がある:

味噌煮込みロジバン: アスペクト論

これらの雑多な考察をちゃんとまとめようかなとしていて、停滞中である。

zi'o と tag の話

iuk.hateblo.jp

iuk.hateblo.jp

iuk.hateblo.jp

zi'o と tag を対としてみてスッキリした見解を得たいという試みも未だ終わっていませんね。

ちなみにこの話は結構前からやっていたようです: 味噌煮込みロジバン: zi'o と sumtcita sumtiを対とみる

by standard まわりの修正

分かりにくいsumti位相談所

辞書定義における "by standard" などの日本語訳が結構ブレてて、それを統一したいなと思っていた事案。結局やってない。

ロジバンにおける化合物命名

lela.iúk.tánxe - lojbo xukmi bo cmene -ロジバンにおける化合物命名-

これも途中で止まってしまっている…。まあこれは優先度低いかな。


というわけで、結局やってない祭りでした。独自研究系はともかくとして、おかゆはとりあえず早くはじめてのロジバン第二版を仕上げないといけないですね。反省します。

「実践Python3」の Template method パターンが

なんかこれで確信したけど、散々過去に悩んだコレも「実践Python3」の捉え方が変なんだろうってことにしておく:

iuk.hateblo.jp

さておき

Template method パターンと Factory method パターンの語の(Pythonにおける)意味がやっと分かってきたからメモ。

この2つは名前の通り、そういうメソッドを作っておこう!っていうパターンで、それぞれのメソッドが「テンプレート的」か「ファクトリー的」かってことですね。

Template method は そのクラスがもつ他の抽象メソッド を使って書かれた、より大きな操作をするメソッド。これは ABCで実装されて、その具象クラスは抽象メソッドを実装すると同時に、この template method も使えるようになるって寸法よ!素敵! Template methodパターンは、ABCじゃなくて基底クラスを使ってもいい。その場合は、template method 内で使われる他のメソッドというのが抽象メソッドではなくてデフォルト実装されたメソッドになる。

一方、Factory method は、ABC では抽象メソッドとして定義されるメソッド。で、具象クラスにおいてファクトリーとして働く、つまり、特定のインターフェースを備えたオブジェクトを吐き出すメソッドとして実装される。

「なんで特定のインターフェイスを備えたやつじゃないといかんのか?」ということについては、他のところでそういうインターフェース持ってる前提で色々書いちゃうからでしょうな。

ということを考えると、Template method で使う 抽象メソッド の中には大雑把には Factory method も含まれる。ただし厳密にいえば、それは抽象メソッドではなくて抽象オブジェクト(具体的にそれがどんなものか決まってない(インターフェースしか分からん)という意味での抽象)なので、ちゃんと区別するに値はするのかな?という感じ。

生成されるオブジェクトのインターフェースに従ってあーだこーだするという点で template method パターンよりも手の込んだ感じしますよね。そういう感じよ(?)

使用する抽象的なのが自身のクラス内のメソッドで完結するのが template method パターン、インターフェースの要請だけしておいて、外部からオブジェクトもらってこようとするのが Factory method パターンかなと理解した。

ただ、この書き方だと、「Template method パターンにさらに Factory method パターンを適用したもの」という側面でしか Factory method パターンを描写できてない気がする。

でも、「Template Methodパターンをオブジェクト生成の場面に適応させたデザインパターンと言えます」*1 らしいので、これでいいのかもしれない。

いずれにせよ、Template/Factory method パターンどちらも、「上位クラスが下位クラスに部品(メソッド)の実装丸投げするパターン」ってことだろう。

そういう意味で、このパターンはクラスとクラスのパターン(クラスパターン)らしい*2

他のパターンとのつながり

ちょっと変えたら別のパターンになるってのが結構あるっぽい。

Strategy パターン

一定の処理とか関数をアウトソーシング化してしまおうぜっていうパターン。Template/Factory method パターンでは、サブクラスの定義で自由度がなくなってしまう(メソッドとかが一意に定まる)けど、Strategy パターンは処理・関数を引数化してしまうことで自由度をあげられる。

あと、クラスとクラスのパターンから、オブジェクトとオブジェクトのパターン(だよね?)に持ち込めるので、ABCとか使わなくていいという意味では楽。

Factory method パターンにおけるサブクラスの実装バリエーションが増えてきたら Strategy パターンに移行すればいいんじゃないかな。たとえば Factory method を3種定義するABCを作るとして、それぞれのメソッドの実装(どのクラスのインスタンスをつくるか)の通りが5つあるとしたら、完全に網羅するには 53 = 125 ものサブクラスが必要になるわけで、そうなると早々に引数化してしまったほうがいい。

もちろん引数化するというのは無用な柔軟さを与えてしまうことにもなるので、そこのところはトレードオフでしょうね。

Bridge パターン

UML図的には Strategy パターンと同じらしい*3

Strategy パターンの UML クラス図は Bridge パターンのものと同じである。しかし、これら二つのデザインパターンはその意図が同じではない。Strategy パターンは 振る舞い に対するパターンであるが、Bridge パターンは 構造 に対するパターンである。

こういう、絵面的には同じだけど意図が違うってパターン割とあるっぽいよね。

Strategy パターンは「振る舞いのアウトソーシング」で、Bridge パターンは割と単純に「モノの分離」。

抽象メソッドの実装という形ではなくて、欲しいモノは引数としてもらおうというパターン。

「xを食べる男」抽象クラスを具象化して「リンゴを食べる男」「バナナを食べる男」クラスを作るんじゃなくて、「xを食べる男」クラスを作っておいて、そのインスタンスの引数に食べ物をとって「リンゴを食べる男」「バナナを食べる男」インスタンス作ろうって話(たぶん)。

いざ「xを食べる男」クラスのサブクラスを作ろうとしたときに対応しやすいのが動機。

Abstract Factory パターン

Factory Method と Abstract Factory の違いを順に理解する | Futurismo より:

Abstract Factory は Factory Method のカプセル化に過ぎないことを示す.

構造的な側面だけに着目すれば、たしかにカプセル化にすぎないかなと思うけど、デザインパターンは構造的な側面だけに注目して理解するものでもなさそうだしね(Strategy/Bridgeパターン然り)。

Factory method パターンでは、その抽象なファクトリーメソッドを使って、より大きい処理をしようとするのはそのクラス自身(つまりそういうメソッドをもつ)。一方、Abstract Factory パターンでは、そういう大きい処理をしようとするのはクラスではなくて外部の誰か。そういう意味で、Abstract Factoryパターンはオブジェクトパターン(らしい)。

ファクトリー関数の利点は、共通(固定した)名前で(所定の)インスタンス作れることなわけだから、誰かに使ってもらわないと(しかも、どのインスタンスがきてもいいようなある程度の普遍性をもった処理の中で)あまり生かされているとは言えない。

Factory method パターンは最終的に自分の中に書いた処理のためのパターンで、Abstract Factory パターンは外部の処理のためのパターンだね(繰り返し)。

とはいえ、その意図を除けば、一連の整合性のあるファクトリー関数(メソッド)群をまとめてしまおうというのが Abstract Factory パターン。

結局、ふたをあければファクトリー関数がそこにあるわけで、共通のインターフェースで異なるファクトリー群が使えるというのが Abstract Factory パターンの美味しささね。

とはいえ、「実践Python3」で Template method パターン実演なのに、template method もってない抽象クラスもってきたりするのは草生えたけど、まあ確かに「何もしない」ことも、共通処理の1つに入ると言われれば…首肯せざるをえない。

そういう意味では、抽象クラスにfactory method が使われている共通処理のないようなものもまた factory method パターンに則ってると言える。そう考えると、factory method をカプセル化したものが Abstract factory だ、というのはあながち間違いでもないのかもしれない。

コーラブルオブジェクトをイテレータ化する

「実践Python3」の一部事項のメモ

__call__ メソッドを実装したクラスのインスタンスなり、関数なり、バウンドメソッドなり。コーラブルオブジェクトは呼び出し(とそのときに渡される引数)に応じて何か値を返したり、どっかの内部状態(IOとか自身の属性とか)を変えたりしてくれる。

普通はコーラブルオブジェクトをイテレータ化しようとは思わないというか、イテレータ化の目処が立たないですが、呼び出しによって自身の内部状態を変えながら値を返してくれるマン(カウンターのような)なら少しその気がありますね。

# coding=utf-8

class C:
    def __init__(self):
        self.i = 0

    def count(self):
        print("exec.", end=" ")
        self.i += 1
        return self.i

この c.countc.i が9になるまで回したいとき、まず思いつくのは for 文です:

c = C()

for _ in range(9):
    print(c.count())

ただ、これは「値を 9 まで回す」、ではなくて、「c.count を 9回実行する」なので、少し不安定です。

なら、whileを使えばいいような?

c = C()

while c.i != 9:
    print(c.count())

いい感じですが、i がプライベート属性だった場合はこの方法は使えません。ちょっと回りくどいですが、

c = C()
i = 0
while i != 9:
    i = c.count()
    print(i)

としてやれば確かに機能します。

結局、for では単純に回数しか、while では別変数や属性を用いて値を監視しながら回すことになります。

もっとこう、c.count の吐き出した値だけを見てよしなに回せたりしないかなあ?

c = C()
for elem in iter(c.count, 10):
    print(elem)

iter関数は引数を2つ取った場合、コーラブルイテレータをつくりだすそう。x1にコーラブルオブジェクトを、x2にセンチネル値(その値が返されたらイテレータを閉めるような値)を入れます。

type を見てみると、<class 'callable_iterator'> でした。

上の実行結果です:

exec. 1
exec. 2
exec. 3
exec. 4
exec. 5
exec. 6
exec. 7
exec. 8
exec. 9
exec.

コーラブルイテレータは、next で次の要素を吐き出す際に、まず第一引数に取ったコーラブルオブジェクトを呼び出す。

今回は c.count が呼び出され、print("exec.", end=" ")が実行されたあと、値が返される。

コーラブルオブジェクトが返した値をセンチネル値と比較し、等しくなければnextの値として採用して吐き出す。

もしリターン値がセンチネル値に一致した場合、nextStopIterationを raise する。

上の結果では、10回目のnextで呼び出されたコーラブルオブジェクトのprint文は実行されていますが、その返り値(10)はセンチネル値と等しいためにelemに渡されずイテレータが止まります。

2. 組み込み関数 — Python 3.5.2 ドキュメント より:

第二引数 sentinel が与えられているなら、 object は呼び出し可能オブジェクトでなければなりません。この場合に生成されるイテレータは、 __next__() を呼ぶ毎に object を引数無しで呼び出します。返された値が sentinel と等しければ、 StopIteration が送出され、そうでなければ、戻り値がそのまま返されます。

コーラブルオブジェクトはnextの度に引数無しで呼び出されるので、呼び出す際に何か値を渡したいというときにはもう少し工夫しないといけない。

イテレート中、同じ引数を与えたい場合

lambda: callable_obj(a, b, c) みたくすればOK。たとえばさっきのクラスに

def count_add(self, j):
    self.i += 1
    return self.i + j

を追加して、j=5イテレータを回したいとしたら、

for elem in iter(lambda: C().count_add(5), 9):
    ...

とすればいい。

イテレータ中、異なる引数を与えたい場合

いやそれもうその引数をリストにして for 文回したほうがよくない?

c = C()
for j in [1, 3, 2, 5, 2]:
    tmp = c.count_add(j)
    if tmp == 9:
        break
    else:
        print(tmp)
else:
    raise ValueError("not become 9.")

forelse は完全に回りきっちゃったときにだけ実行される部分ですな


こう、なんか使えそうで使えなさそうでちょっと使えそうな感じですね。

センチネル値にちょうど一致しない限り止まってくれないので、もしその値を飛び越えちゃったら無限ループします。

でも、コーラブルオブジェクトがStopIterationを上げてくれたときは、それをnextが受け継いで吐いてくれるので止まります。

ただ、コーラブルオブジェクト内にそういう制御を書くなら(i.e. 元々イテレータ用にコーラブルオブジェクトを書くくらいなら)、ジェネレータ使ったほうが…って気もする…。

「いや、lambda: next(generator) とセンチネル値で、途中で止まるようなイテレータを作れるじゃん!」

itertools.takewhile でよくない?」

10.1. itertools — 効率的なループ実行のためのイテレータ生成関数 — Python 3.5.2 ドキュメント

ジェネレータ使ってるなら、素直にifでセンチネル値一致の分岐させたほうがいいと思うけど…。

あっ、これあれか、組み込みのイテレータプロトコルを使わない場合のイテレータの作り方に相当するのか?(とすれば、組み込みでイテレータプロトコルのある(さらにいえばもっと簡単にジェネレータまである)Pythonにはあんまり必要ないのかもしれない(もっと内部のところで使ってたりするのかな?))

括弧を憎みすぎた人間の末路(Pythonで関数合成)

本実装はともかく、ちょっと試しにprintしてみたいときあるじゃないですか。そういうときに、

print(f(g(h(1, 2))))

などと、括弧が多すぎて死にそうになることがある。

まあこれくらい我慢しろっても思うんだけど、ちょっと機嫌が悪くてブチ切れた

魔法少女になって括弧を消し去りたいッ!

せめて関数合成を

functoolsモジュールに関数合成のためのツールあるかなと思ったらなかった…作るしかない…。

というわけで作ったのがこれ。Composableクラス。

class Composable:
    def __init__(self, callable_obj):
        self.__callable = callable_obj

    def __call__(self, *args, **kwds):
        return self.__callable(*args, **kwds)

    def __matmul__(self, other):
        @Composable
        def composite_function(*args, **kwds):
            return self(other(*args, **kwds))
        return composite_function

    def __imatmul__(self, other):
        return self @ other
        
    def __getattr__(self, name):
        return getattr(self.__callable, name)

Composable を関数デコレータとして使うことで@演算子を2関数に使うことができるようになる。

@Composable
def add_10(n):
    return 10 + n

@Composable
def product_3(n):
    return 3 * n

print((add_10 @ product_3)(10)) # => 40

これで入れ子の括弧はかなり無くなる!嬉しさがある。

def chain(*func):
    composite = Composable(lambda x: x)
    for func in func_rest:
        composite @= Composable(func)
    return composite

print(chain(add_10, add_10, product_3)(3)) # => 29

ついでにこういうのも作っておいたので、これでなんとかしてもいい。

殲滅させたい

でも括弧を憎みすぎて、もっと括弧を減らしたかった。というわけで魔改造したのがこれ。

class Composable:
    def __init__(self, callable_obj):
        self.__callable = callable_obj

    def __call__(self, *args, **kwds):
        return self.__callable(*args, **kwds)

    def __matmul__(self, other):
        @Composable
        def composite_function(*args, **kwds):
            return self(other(*args, **kwds))
        return composite_function

    def __imatmul__(self, other):
        return self @ other

    def __rshift__(self, other):
        return other(self)

    def __rrshift__(self, other):
        return self(other)

    def __mod__(self, other):
        return self.apply(other)

    def apply(self, *applied_args, **applied_kwds):
        @Composable
        def applied_function(*args, **kwds):
            return self(*applied_args, *args, **applied_kwds, **kwds)
        return applied_function

    def __getattr__(self, name):
        return getattr(self.__callable, name)
@Composable
def xruti(func):
    return func()

@Composable
def add_10(n):
    return 10 + n

@Composable
def product_3(n):
    return 3 * n

@Composable
def add(n, m):
    return n + m

@Composable
def sub(n, m):
    return n - m

@Composable
def product(n, m):
    return n * m


print((sub % 200 @ add % 50 @ product % 4 @ add % 5)(10)) #(1)
print(10 >> add % 5 >> product % 4 >> add % 50 >> sub % 200) #(2)
print(sub % 5 % 1 >> xruti) #(3)

多分3日後の自分は理解できない

まず (1) はさっきと同じで関数合成してるけど、部分適用の % をぶち作った。

(2)では、>> を導入。

こういうときって、「引数にほにゃして、もにゃして、ぽちゃして、どみゃして」って思考なのに関数で書くと逆になるのがイヤ!

ならメソッドチェーンで書けばいいんだけど、Python は絶妙にメソッドチェーンできなくて辛いし…。

なので、>>に左の値を右の関数にぶち込んで値を返すということをしてもらって、括弧をなくしました。

(3) は % がちょっとポンコツで、全部値が埋まってても値を返さずになお関数オブジェクトを返してくるので、xruti関数(ロジバンで "return")を使って値を返すように改造してある。

「キーワード引数」?知らん!!!!!!!!!

お気を確かに

確かに関数で包みまくってると嫌になりますが、まあ流石に上はやり過ぎ感がある。

もう少し穏当にするならまあこんな感じだろうか。

from functools import reduce
def compose(callables):
    callables.reverse()
    def apply(*args, **kwds):
        accum = callables.pop(0)(*args, **kwds)
        return reduce((lambda x, f: f(x)), callables, accum)
    return apply
print(compose([product_3, add_10, product_3, add_10])(10)) #=> 210

引数はアンパックしてもいいかもね。まあこれくらいが平和かも