見出し画像

Retro-gaming and so on

余計なお世話、再び(笑)

また星田さんの記事に勝手に答えていこうと思う(笑)。

余計なお世話、第二弾である(笑)。

↑ここ衝撃でした。条件分岐そのものを消してしまうとか・・僕には絶対に思いつかないわ~と 

うん、僕個人でも絶対思いつかないですね(笑)。
要するに何が違うのか、と言うと、僕が関数型言語でのノウハウをある程度知ってるから、に過ぎないから、です。
それくらい、「プログラミングの基本」と思われてる素のC言語と関数型言語で「出来る事」に差がある、って事なのです。
前者はそのままじゃ出来る事が少ない、後者は「元々出来る事が多い」から、プログラミングに於いて出てくるテクニックに結果差が出てきて、前者で後者のようにプログラミングするには山のように「余計な事柄」をやらないと到達出来ない。

CやPascalなんかの古典的・・・うん、もう「古典的」だよな、なプログラミング言語とPythonや関数型言語の差がまずはどこにあるのか、と言うと、リストの存在です。あるいは可変長な配列つってもいいんだけど。
Pythonは実は必ずしも関数型言語で実装してる「リスト」を備えてるわけじゃないんだけど、それでもリストがあるお陰で素のCでは考えられない程自由にデータを設計する事が出来る。
そう、これはデータ設計とその自由度の問題なんだ。
例えば、C言語っぽくリストで次のようなデータを設計するとする。

>>> table = ["https://blog.goo.ne.jp/hosidaosuteo", "https://blog.goo.ne.jp/isamrx72", "https://blog.goo.ne.jp/cametan_42"]
>>>

3つくらいアドレスを記録したtableを設計する。一つ目は星田さんのブログのアドレスなんだけど、じゃあ、星田さんのブログのアドレスを取り出すにはどうすれば良いのか。
C言語的な発想だと、「配列の0番目の要素」としてアクセスしなければならない。そうね、インデックスが重要になるわけ。
でもプログラミングしてる最中に「星田さんのブログは0番目に入れてたから・・・」って暗記してなきゃなんない。これはメンド臭いでしょう。
ここである人が考えついた。

「インデックスの代わりに名前でアクセス出来たらエエんちゃうの?」

と。
この人が考えた「データ構造」が次のような形式なわけね。

>>> table = [["星田オステオパシー", "https://blog.goo.ne.jp/hosidaosuteo"], ["新しいアカウントで始めました。", "https://blog.goo.ne.jp/isamrx72"], ["Retro-gaming and so on", "https://blog.goo.ne.jp/cametan_42"]]
>>>

単純に二次元リストにして、名前とデータのカップリングをリストに収める事にした。別に新しいデータを設計したわけじゃなくって、既存のリストを使ってデータ構造を作った、って事ね。
この形式のデータ構造を「連想リスト」と呼びます。このお陰で僕らは忌まわしいインデックスから開放される事となった。
アクセスは次のような関数を設計して行う。

def assoc(key, alist):
 for item in alist:
  if key == item[0]:
   return item

こういう関数を設定しておけば、「インデックスが何番なのか」覚えてなくても、即座に要素にアクセスが可能となります。

>>> assoc("星田オステオパシー", table)
['星田オステオパシー', 'https://blog.goo.ne.jp/hosidaosuteo']
>>> assoc("新しいアカウントで始めました。", table)
['新しいアカウントで始めました。', 'https://blog.goo.ne.jp/isamrx72']
>>> assoc("Retro-gaming and so on", table)
['Retro-gaming and so on', 'https://blog.goo.ne.jp/cametan_42']
>>>

またリストは可変長なんで要素を追加するのも簡単。次のような関数を作ります。

def alist_cons(key, val, alist):
 return [[key, val]] + alist

そうすれば例えば、

>>> table = alist_cons("シン・MOEヨ日本ト世界(仮称)", "https://blog.goo.ne.jp/blue_031", table)
>>> table
[['シン・MOEヨ日本ト世界(仮称)', 'https://blog.goo.ne.jp/blue_031'], ['星田オステオパシー', 'https://blog.goo.ne.jp/hosidaosuteo'], ['新しいアカウントで始めました。', 'https://blog.goo.ne.jp/isamrx72'], ['Retro-gaming and so on', 'https://blog.goo.ne.jp/cametan_42']]
>>>

として新しくデータを追加する事が可能となる。
これは言い換えればプログラミング言語が原初的なデータベースを持つ事が可能になった、と言う事です。そして関数型言語はこれ、つまり連想リストを取っ掛かりとしつつプログラミング技法を長い時間をかけて発展させていく事となったのです。
反面、この設計には一つ難がある。assocの定義を見てみれば分かるでしょうが、「探すデータが最初にある方がアクセスは速い」と言う事。逆に言うと、連想リストの右、っつーかケツの方に行けば行くほどアクセス時間が長くかかる、と言う欠点があるわけです。ルーピングする以上当然で、ルーピングする回数が少なければ少ない程良い、と。
この欠点を解消するには、やっぱプログラミング言語そのものに手を加えなければならない、と言う事。
そういう理由で登場したのが、「連想リスト専用のデータ構造」、ハッシュテーブルです。Pythonで言うトコの辞書型、RubyやJavaScriptでは「連想配列」と呼ばれています。すべてハッシュ法と呼ばれるテクニックを用いて、データがどこに格納されていようと定数時間で検索が終わるように設計されています(逆に言うと、あまり大きくないハッシュテーブルを相手にする場合は、それなりに計算コストがかかる、と言う欠点があります)。

この連想リスト、ないしはハッシュテーブルが出てきた事により、もう原理的であるassocの定義を見てみれば明らかなんだけど、場合によっては条件分岐を行う必要がなくなった、って事が分かるでしょう。だって勝手に探してくれるんだもん(笑)。
それどころか、とてつもなく強力な事が可能となる。
実例を挙げましょう。

このブログ、で面白い事にトライしている。

Pythonはオブジェクト指向言語らしく、ポリモーフィズムと言う機能があります。
良く挙げられる例としては"+"。数値相手だと単なる足し算ですが、文字列相手だと文字列の連結、と言う「直感的には正しくても実装上不思議な挙動」をする。

>>> 1 + 2
3
>>> "hoge" + "fuga"
'hogefuga'
>>>

このブログの著者、isamさんは、ポリモーフィズムっぽく数値でも文字列でも引き算出来る関数を書こうとしている。
アイディアは素晴らしい。そして、辞書型を使うと次のような事が可能なのです。

def Hikizan(a, b):
 from numbers import Number
 table = {True: lambda x, y: x - y,
     False: lambda x, y: "".join(x.split(y))}
 return table[all([isinstance(i, Number) for i in (a, b)])](a, b)

これで次のようになる。

>>> Hikizan(100, 50)
50
>>> Hikizan("abcdCDefghCDijklCDmn", "CD")
'abcdefghijklmn'
>>>

これはかなり端折った実装ですが、この形式でプログラムを書く方法論をデータ駆動型プログラミングと呼びます。単純に言うと、辞書型とデータ型名を使って自動で関数を振り分ける。
ポイントとしては以下の2点があります。

  1. 条件分岐を用いず、与えられた引数の型を調べて勝手に適した関数を選んでくる。
  2. 辞書型の値は関数がファーストクラスオブジェクトである以上、関数だろうがラムダ式だろうが構わない。
ここではローカルで辞書型を使ってますが、別に大域変数にしても構いません。そうすれば

「もっと別の機能を追加したい」

等と言った場合、簡単に辞書型に新しく関数を追加出来るでしょう。ヴァージョンアップはお手の物です(まぁ、端折った実装なんで、そもそも辞書型に登録する「型」をもっと工夫せねばならないけど)。
この実装のポイントってのは「同じ関数名で別々の事を実行出来る」って事です。カッチョいい言い方をすると名前空間を汚さない。単一のHikizanと言う名称であたかも複数の関数を別々で自動に起動するような効果が得られる。
実の事を言うと、関数型言語界隈ではさしてオブジェクト指向に熱中しない理由がここにあります。オブジェクト指向は同名のメソッドでも別々の機能を持つ事が出来る、ってのがウリの一つなんだけど、関数型言語の長い歴史の中では、こういう連想リスト、ないしはハッシュテーブルを用いて、その辺で全く同じ効果をあげる方法論を既に確立してた、って事なんです。
言い方を変えると同様の事をC言語なんかで行うのは至極厄介です。「出来ない」とは言わないけど、そこに到達するまではメンド臭いプログラミングを延々を行う必要があって、似たことを比較的簡単にやる為にはC++やJavaの登場まで待たなければならなかった。
んで、実はこの10年くらいで注目されてるC++辺りでのジェネリックプログラミング、ってのも原理的にはこのデータ駆動型プログラミングと全く同じです。言い換えると関数型言語での「方法論」はC/C++より遥かに先に進んでた、と言う事なんです。

いずれにせよ、星田さんに見せたテクニック(辞書型で条件分岐を消し去る)は関数型言語では上で見たようにわりかし当たり前のテクニックなんです。
誤解のないように言っておきますが、関数型言語は「簡単」なんで、このように色々なテクニックが研究・開発されてきた、って事です。CやC++、あるいはJavaのように「使うのが難しければ」こんなテクニックを開発する余地がない。だからノウハウがあっても伝授されづらい。
単にそれだけ、の話なんですね。
関数型言語はむしろ簡単なプログラミング言語で、Pythonはその血を引いている。ただ、例えばCからやってきた人たちはそれを知らんので、こういうノウハウを教えてくれないだけ、なんですよ。

rgb(s)のsって変数どこから入力されてるの?とリストを探し回る。2回読んで「あ、for i in  の i と一緒か・・(?)」と。あとの方まで読むとリスト内包表記で入力される i を受け取って加工するなりして返すと言う機能のための関数の中でだけ一時的に使われる変数ってこと・・かな

はい。全部正解です。
rgb(s)s仮引数と呼びます。
当然無引数の関数もあるんだけど、一応、スタンダードな関数では仮引数を用いて定義を行います。「外から入れる加工する対象の何か」ですね。
例えばPythonのみんな大好きprintとか、次のように定義されてますが。

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

*objects、 sep=' '、 end='\n'、 file=sys.stdout、 flush=Falseってのは全部仮引数です。んで、「=」が付いてるのはデフォルト引数と呼ばれる形式で、特に何か与えない場合、自動で指定したブツを引数に代入してくれる、と言う仕組みです。
例えば、end='\n'は何も指定しないとendと言う仮引数には'\n'が代入される、と言う意味です。ここでprintは必ず行末で改行する、と言う制御をしてます。

>>> print("hoge")
hoge
>>> print("hoge", end = "!\n")
hoge!
>>>

上の例のように、仮にend"!\n"を与えたら行末に"!"を付け足して改行しますね。
このように、関数はほぼ仮引数やデフォルト引数を渡して何かをする、ように設計します。これは自作関数だろうと変わりません。
まぁ、開発中に、例えばrgb(s)みたいに関数を定義した場合、Pythonインタプリタ上で具体的に何か与えて(この場合は文字)、動作を確かめたりします。このように具体的に与えられた引数を実引数と呼びます。



この時、"a"とか"k"とか"s"が実引数ですね。こうやってPythonインタプリタ上で動作テストをしながら、プログラムを組み上げて行くわけです。

これこそ写経を重ねるとパターンとして自然に思い浮かぶようになるのかなぁ

これも全くその通り。
実のトコ、何度も言ってますが、プログラミングと「論理性」はあまり関係がない。
必要なのはなるたけ多くのパターンを知る事、です。
ただ、それを言っちゃうと、プログラマの「神秘性」が損なわれるので(笑)、「論理性が必要」って言ってるだけ、です。
仮に数研出版が「チャート式 基礎からのプログラミング」なんつー本出したら常識が引っくり返りますよ(笑)。それくらい、プログラミング初心者に対する「ノウハウの提示」ってのはあるようで無いんです。

いや、まだ興味はあるんですけど・・学習が面白くないんだもんな・・Pythonの文法とか基本的な事は分かっても


だから?


って感じで。

これは100%正しい。
種を言うと、これもC言語の弊害なんです。と言うか、C言語のバイブル、って言われているK&Rの責に負うトコが多い。
K&Rって本は非常に良く纏められていて、C言語の公式仕様が出来るまで、この本を参考にして色んなC言語実装が作られていた程なんです。要するにリファレンスとしては非常に良くできてる
ところがね〜。この本がバイブルになっちゃったせいで、この本以降で出てくる本ってのは基本的にK&Rの章立てをそのまま借りてくるような本ばっかになったの。これが弊害。
だから結構な確率で入門書とか言いながら、実際はリファレンスのような本ばっか出てきて、文法とビルトインの関数やデータ型の説明に終始したような本ばっかになっちゃったんだ(笑)。読んで面白くねぇ、ってのは全くその通りなの。
結果、大学で授業する分にはいいんだろうけど(大学の授業はどっちみち退屈だし・笑)、そのせいで「如何にプログラミング言語の授業で時間を潰せるか」みたいな状態になっちゃったのね(笑)。
そして、「文法を理解」しても、じゃあ実際「どうやって何かを作るか」って指南は殆ど無い状況になっちゃったのね。
ハッキリ言うけど、かつての「BASICでゲーム作ろうぜ」って本の方がマシなんですよ。必要なテクニックや使うべきデータ型はその都度説明する、みたいな。ただ、それじゃあ大学で授業にならんのね(笑)。結局、「大学で授業する為にどういう本を書くのか」ばっか重要視されるようになった、ってのが大きいんです。
んで、もう一つ言うと、実はプログラミング関連の書籍ってほぼ、実際のトコ、同人誌ばっかなの。出版社の方で企画して信頼出来る著者に依頼する、って形式が殆どないんですよ。逆に「持ち込み企画」が主流なのね。「書きたい、本を出版したい」って人が原稿持ってきてそのまま出版する。実の事言うと、状況は「ラノベ」より酷いんだ(笑)。
それで、出版社側の編集ってのは誤字脱字を修正する、くらいしかやらないのね。その本が「どれくらい分かりやすいのか」とか全然チェックしない。編集がそれでプログラミングを実際やってみる、とかまず無いんですよ。だからワケの分からん本(例えば提示してるプログラムが動かない、とか)が出るハメになる。Amazonとかで批判されてる本が多いのはそれが原因です。
もう何年も経つけど、日本で電子書籍がーとか言う提灯記事が多かったのは殆どIT系出版社が放る記事でしょ?小学館とか集英社とか講談社はそれほど熱意がなかった。今でもそこまで無い。理由は大手出版社は「編集がキチンと仕事をしてるから」。電子出版になったからって劇的にコストダウンするワケがねぇ、って知ってたのね。
反面、同人誌出版状態であるIT系出版社は、大手出版社と違って「編集が仕事をしてない」わけ(笑)。だって誤字脱字しかチェックしないし内容に関して示唆する、とかしないわけじゃん。彼らのアタマの中にはコストダウンしかないわけよ。編集に携わる面倒くささが余計減ってくれればバンザイ、と。それが大手出版社側の電子書籍に対する態度とIT系出版社のそれとは大きく違った理由なんです。
いずれにせよ、そんな背景があるんで、IT系出版社の出版物は初版を売り切れば増刷もありません、とかなってるのね(笑)。もう一回言うけど、事実上同人誌ばっかで、「信頼出来る本」あるいは「信頼出来る出版社」ってのは数が限られてるんです。
ホント、お前らコミケでやってろ、とか思うんだけど(笑)。

baralist[:-1] とか baralist[-1] の意味も曖昧ですわ・・基本が(-_-;)

まぁ、基本が、っつーよりこれがPythonならではのショートカット記法で、あんま他の言語じゃ見られない形式かも。

>>> ls = [1, 2, 3, 4, 5]
>>> ls[0]
1
>>> ls[-1]
5
>>> ls[1:]
[2, 3, 4, 5]
>>> ls[:-1]
[1, 2, 3, 4]
>>> ls[:2]
[1, 2]
>>> ls[-2:]
[4, 5]
>>> 

これはホントラク。言い換えると配列系のデータで如何にインデックスを数えるのがメンド臭いのか、って言う証左なのね(笑)。長さを把握して何番目なのか、とか数えるのはアタマ痛いわけじゃない?大体、リストが伸長したら番号が追加されるので目もアテられない。
まぁ、負の数のインデックスってのは「理論的に考えると」おかしくねぇの?って思えるんだけど、便利さの前では・・・ねぇ(笑)?
Pythonでの極めて優秀なデザインだと思います。

しかし解説を見たら「読める」んだけど、(今のところ)必要に応じて作文できる気がしないw。これを出来るようにするのが写経ってことなのかなぁ・・

そうそう、写経するウチに慣れます(笑)。
っつーかね、写経するのってかなり大事なんですよ。
読んだだけだと理解出来ないけど、自分で実際に打っていくと「ああ、なるほど」とかなる。
写経ってかなり役立つ学習法だと思います。

この話も興味深かったなぁ・・苫米地英人さんの本を読んだりしてるとやたらと出てくるのが「LISP」って言語の話で、自分のことを関数主義者って言うんですよね。

ああそう、苫米地さん知ってるんだ。
日本じゃ主流な人たぁ言えないんだけど、ある意味有名なLisperですよね。うん。
彼を見習うなら・・・・・・うん、一回Lisp触ってみたらいいかもしんない。
ただし、実用性を期待するとアテがハズレます(笑)。ホント、Lispは実用性が皆無なプログラミング言語、って言って良いです。あるのは「理論だけ」なのね。っつーか理論的に一貫してる、ってのがLispの特徴と言って良い。他のプログラミング言語のように、基本的に「実装上の都合により」って言い訳が一番少ない言語なんです。
ハッカーになろう、って文書があって、これはエリック・レイモンドと言う「オープンソース」って単語を発明した人が書いてるんだけど、次のように言ってます。

LISP を勉強しておきたいのは、別の理由からです――それをモノにしたときにすばらしい悟り体験が得られるのです。この体験は、その後の人生でよりよいプログラマーとなる手助けとなるはずです。たとえ、実際には LISP そのものをあまり使わなくても。 

そう悟りを開くための言語、ってのがLISPです。何か抽象的なんだけど。
この文書ではこのような証言が紹介されています。

Comp.lang.python のあるメッセージによれば 「自分は Python で遊ぶようになるまで、なぜ LISP がそんなにいいアイデアなのか わからなかった」とのこと

これが示してるのは、ある程度PythonとLISPは近い、と言う事。そしてLISPを理解する事によってPythonも理解出来る、と言う事。
実際的な意味で言うと、これが「悟り」の一つでしょう。

いずれにせよ、苫米地さんを通じてLISPを知ってるなら、LISPを触ってみた方がいい。実用性がない、ってのはその通りなので、実際自分がプログラムを書く際にはPythonを使い、「インタプリタで遊ぶ」のはLISPにすれば良い、って事。相乗効果で色んな事を「悟って」行くでしょう。

ところで以前書いたんだけどLISPには標準がない。厳密に言うと、国際標準があっても実装が殆どない、と言うワケが分からん状況だ。ISO(国際標準化機構)でC/C++は定義されてるんだけど、同じような定義があってもLISPには国際標準に準じた実装がほぼない、と言う事。
ちなみにPythonにはそういう「国際標準」はない。けど、(殆ど)唯一単独の実装なので、Pythonは基本的に僕らが使ってるPythonしかない(いくつか別の実験的実装はあるけど)。反面、C/C++はMicrosoftを含む色んな人たちや色んなグループ、企業がコンパイラを作って配布したり売ったりしている。Lispはそういう「国際標準を実装して提供」されてない、ってワケだ(ちなみに、RubyはC/C++同様に「国際標準」がある)。
話がややこしいのは、LISPはプログラミング言語の中では割に簡単にプログラミング出来てしまうプログラミング言語で、世の中には探せば何百個もの「俺様LISP」が存在する。そういうのを纏めて「LISP方言」と呼びます。

そのLISP方言、の中で、苫米地さんが使ってるのが「ANSI Common Lisp」と呼ばれる方言。ANSIは「アメリカ規格協会」の事で、結局この規格はアメリカローカルの国内規格である。従って、例えばJIS(日本産業規格)では対応規格がない。よって日本やヨーロッパの国々の視点で見ると「単なるアメリカローカル規格」ってわけなのね。
WindowsでANSI Common Lispを試す場合、Lispboxを使うといいです。これはGNU EmacsをIDEと見なしたオールインワンの開発環境です。現在インクルードされているANSI Common Lisp処理系はオープンソースのClozure CLで、最速か二番手か、と言われるくらいの処理系です。
難点は、Emacsの変態キーバインド(※1)。Windowsズッポシだとちとこの環境は慣れないかもしんない。
ただ、それさえ目を瞑れば、ANSI Common Lispなら最高/最強の環境である事だけは間違いがないです。

個人的に一番オススメなのは、いつも言ってる通りRacketと言うLisp方言を使う事。こっちもIDE完備で、また上のLispboxと違い変態キーバインドとは縁がない。Windowsのフツーのソフトウェアのように使う事が出来ます。
そして、恐らくRacketが世界で一番使われているLisp方言ですね。


Run(実行)ボタンがあったり、と昔のBASICを彷彿とさせます。
なお、Racketは単独実装だけど、実はSchemeと呼ばれるLisp方言のそのまた方言です。
Pythonに関してはこの文書では次のように書かれてます。

Python は Scheme の (よいライブラリをもった) 実用的なバージョン

つまり、今後もPythonを使っていくとしたら、PythonはANSI Common LispよりはSchemeに近い、と言う事をこの文書は暗示してます。
よってLispで遊ぶとしてSchemeを選ぶのなら、相乗効果はかなり期待出来るでしょう。
また別のハッカーは次のような事を書いている

あなたはまたLispも知る必要がある。別に実際の仕事に使う必要はない。もっとも、多くのGNUアプリケーションにはLispは思いがけず役に立つものなのだが。特にLispの小さく純粋な方言であるSchemeを学ぶといい。GNU版のScheme実装はGuileと呼ばれている。
MIT(※2)とバークレーでは新入生にSchemeを1学期か2学期教えている。学生はなんでそんな奇妙な言語を学んでいるのか見当もつかない。正直なところ、Schemeは最初に学ぶ言語としてはひどいものだ。そしておそらくは2番目としても。あなたはいつかそれを学ぶべきだが、最初と2番目は避けておいた方がいい。
Lispを学ぶのは簡単ではない。大きな飛躍がいるのだ。CみたいなプログラムをLispで書けるというのでは十分でない。そんなのは無意味だ。CとLispはスペクトルの反対の端に位置している。他方が上手く扱えない領域で大きな力を発揮するのだ。
Cがコンピュータがどう動作するかのモデル化に最も適した言語とすると、Lispは計算というものがどう振る舞うかをモデル化するのに最も適した言語だ。ほんとのことを言って、Lispについて多くのことを知る必要はない。一番シンプルでクリーンなSchemeを使い続けることだ。他のLisp方言はライブラリやらツールやらを備え、C++やJavaが持つような大きく複雑なプログラミング環境へと成長している。そういう部分については知っている必要はない。ただSchemeでプログラムを書ける必要がある。The Little Schemer と The Seasoned Schemerの練習問題を自力ですべて解ければ十分だと思う。たぶん。

RacketはSchemeと必ずしも全部同じじゃないけど、最小のSchemeを学ぶには良い環境を提供してくれるでしょう。
Racketを学ぶ場合、このサイトが日本語では一番まとまってて優秀なサイトだと思います。僕もこのサイトでSchemeを学びました。

んで、実の事を言えば。上のLispboxやRacketよりも前にインストールして試してもらいたいプログラムがある。
それがこれです。
  • 魔法言語リリカル☆Lisp(※3)
冗談みたいな話ですが、マジです(笑)。



実はこれは同人ソフトなんですが、Lispの取っ掛かりとしては非常に優れている。
構成としては全12章からなるアドベンチャーゲーム方式なんですが、後に行けば行くほど、練習問題の難易度が高くなっていって、最後なんぞチャーチ数なんてモノが顔を出す始末(笑)。舐めてはいけない。



結構歯ごたえがある練習問題が用意されてて、定型的なLispでの問題なんだけど、Lispの真髄(の少なくとも一部)を味わえるようになっています。
僕は全然、元ネタの「魔法少女リリカル☆なのは」とか知らんかったんですが、関係なくプレイ出来たんで、多分大丈夫でしょう。

今回は取り敢えずこんなトコかな?

※1: Emacsの基本キーバインド集はここで公開されている。
※2: MIT(マサチューセッツ工科大学)では今やSchemeを教えずに、やはりPythonがその位置を取って代わっている。これが基本となってるMITでのPythonの教科書である。
ただし、3章辺りで「PythonでSchemeを実装してみようぜ?」ってネタになってる辺り、相変わらずMITである(笑)。
※3: サイトへリンクを貼りたいんだが、何故か「本文に不正な書式が含まれています。」となって投稿出来ずに下書きも保存出来なくなってしまう。goo blogの恐ろしくクソな側面がまたしも出てきてしまった。
そもそも「本文に不正な書式が含まれています。」と表示するにせよ、それがどこにあるのか分からないようなショボい警告ではどうしようもないのでは?
goo blogはホンマ、ロクなブログではない、と言う事である。
  • Xでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

最近の「プログラミング」カテゴリーもっと見る

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